<?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>Build and Release &#8211; Best DevOps</title>
	<atom:link href="https://www.bestdevops.com/category/build-and-release/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bestdevops.com</link>
	<description>Lets Learn, Do it &#38; Share! Thats a Best DevOps!!!</description>
	<lastBuildDate>Tue, 13 Oct 2026 21:03:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>How can we become Certified Jenkins Engineers (CJE)?</title>
		<link>https://www.bestdevops.com/how-we-can-become-certified-jenkins-engineers-cje/</link>
		
		<dc:creator><![CDATA[rahulkr]]></dc:creator>
		<pubDate>Sat, 14 Aug 2021 12:37:35 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Continuous Delivery]]></category>
		<category><![CDATA[Continuous Deployment]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Benefits]]></category>
		<category><![CDATA[certifications]]></category>
		<category><![CDATA[Courses]]></category>
		<category><![CDATA[Jenkins Engineer]]></category>
		<category><![CDATA[Training and Certification]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=19073</guid>

					<description><![CDATA[What is a Jenkins? Friends as you already know that software development is a very huge and heavy process. There [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading"><strong>What is a Jenkins?</strong></h1>



<div class="wp-block-image"><figure class="alignright size-full is-resized"><img fetchpriority="high" decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/08/certified-jenkins-enginner.png" alt="" class="wp-image-19074" width="579" height="304" srcset="https://www.bestdevops.com/wp-content/uploads/2021/08/certified-jenkins-enginner.png 600w, https://www.bestdevops.com/wp-content/uploads/2021/08/certified-jenkins-enginner-300x158.png 300w" sizes="(max-width: 579px) 100vw, 579px" /></figure></div>



<p class="wp-block-paragraph">Friends as you already know that software development is a very huge and heavy process. There are so many innumerable moving parts of it. In order to improve the development process, we utilize the methodology of DevOps and its tools. In DevOps, there are so many phases. This is one of the most favorable phases as continuous integration which is willing to help you in coming all together with the parts of software development and manages all of them. Therefore, there is a very popular tool named ‘Jenkins’.</p>



<p class="wp-block-paragraph">&nbsp;Jenkins is an open-source automation tool. Now, we will learn about continuous integration and using it in Jenkins. It is a phase of DevOps in which we are continuously doing integrate all of your software development processes in parts and take parts to combine all together. Well, we say combine but it actually controls through continuous integration.</p>



<h1 class="wp-block-heading"><strong>What are the benefits of Jenkins?</strong></h1>



<p class="wp-block-paragraph">Take a brief history of Jenkins. Jenkins was originally developed in 2004 by the sun microsystems company under the name Hudson. It had slowly gained popularity and had become one of the best developing tools out there. After this, the project was later named Jenkins when oracle bought microsystems and decided to keep Hudson &amp; Jenkins as separate entities. It is now one of the most popular CI/CD tools in use out there. As we can see certain benefits are associated with:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/08/pic1.png" alt="" class="wp-image-19075" width="714" height="253" srcset="https://www.bestdevops.com/wp-content/uploads/2021/08/pic1.png 624w, https://www.bestdevops.com/wp-content/uploads/2021/08/pic1-300x106.png 300w" sizes="(max-width: 714px) 100vw, 714px" /></figure>



<ul class="wp-block-list"><li><strong>Jenkins is a community tool – its open source and has a very large community that contributes to it regularly.</strong></li><li><strong>Its free so you don’t have to accrue anymore subscription costs</strong></li><li><strong>Easy for the developers to find and fix issues.</strong></li><li><strong>Improves code quality, minimize defects.</strong></li></ul>



<h1 class="wp-block-heading"><strong>Why we should learn Jenkins?</strong></h1>



<p class="wp-block-paragraph">After getting the benefits of Jenkins. Now, looking for the learning process. We are learning for using it. We use it for seeing widely use through DevOps team, build and release teams, and dev teams. Due to it provides feedback loop back to the developer and fix the errors. It developer has fresh in the memory for quick error. It can publish every build of your software and has already gone through automation testing. Further uses associates with this such as easy interface, easy to navigate, easy document and example, free and open-source, plugin and functionality, and users around the world.</p>



<h1 class="wp-block-heading"><strong>How our Jenkins course/training would help?</strong></h1>



<div class="wp-block-image"><figure class="alignright size-full is-resized"><img decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/08/Building-a-dev2Ftest2Fprod-Pipeline-with-Jenkins-1-881x441-1.jpg" alt="" class="wp-image-19076" width="645" height="323" srcset="https://www.bestdevops.com/wp-content/uploads/2021/08/Building-a-dev2Ftest2Fprod-Pipeline-with-Jenkins-1-881x441-1.jpg 881w, https://www.bestdevops.com/wp-content/uploads/2021/08/Building-a-dev2Ftest2Fprod-Pipeline-with-Jenkins-1-881x441-1-300x150.jpg 300w, https://www.bestdevops.com/wp-content/uploads/2021/08/Building-a-dev2Ftest2Fprod-Pipeline-with-Jenkins-1-881x441-1-768x384.jpg 768w" sizes="(max-width: 645px) 100vw, 645px" /></figure></div>



<p class="wp-block-paragraph">Through the course tutorial, we get intact knowledge and practices that help you in working along with the Jenkins. It allows you to create build jobs on certain kinds of projects such as freestyle projects, pipelines, multi-configuration projects, multi-branch pipelines, folders, and GitHub organizations. After this we are getting benefitted from tutorials in two items, one is the Jenkins freestyle job it comes under many configures as general, source code management, build triggers, build environment, build, and post-build actions. Another is the pipeline, it comes with certain stages as CI/CD pipeline, Jenkins file, and Jenkins pipeline. I hope this will make you clearer to understand about the tool, their automation process, and software development process connections with different phases by using different plugins depending upon your needs. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Developing an Embedded Software Build Pipeline: A Practical Guide</title>
		<link>https://www.bestdevops.com/developing-an-embedded-software-build-pipeline/</link>
					<comments>https://www.bestdevops.com/developing-an-embedded-software-build-pipeline/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Fri, 06 Dec 2019 06:51:52 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[Build-Pipeline]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Servers]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=9437</guid>

					<description><![CDATA[Embedded software development has historically lagged behind mainstream software practices. Learn how to build a modern, automated CI/CD pipeline specifically designed for embedded systems teams.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on concepts originally published at designnews.com. The observations and recommendations reflect common patterns in embedded software development practice.</em></p>



<h2 class="wp-block-heading">Why Embedded Software Teams Need Better Build Pipelines</h2>



<p class="wp-block-paragraph">Embedded software development has long trailed the broader software industry when it comes to adopting modern engineering practices. In the late 1990s, the push was simply to move away from assembly language and toward structured C development. Today, while the general software industry has standardized on build pipelines, continuous integration, automated testing, and CI/CD workflows, many embedded teams — particularly at smaller companies — are still relying on largely manual, ad-hoc processes.</p>



<p class="wp-block-paragraph">The gap matters. A well-designed build pipeline does not just speed up software delivery — it improves quality, reduces debugging time, lowers project costs, and makes firmware deployments more predictable and repeatable. This article explains what a modern embedded software build pipeline looks like, and how teams can incrementally implement one.</p>



<h2 class="wp-block-heading">What Is a Software Build Pipeline?</h2>



<p class="wp-block-paragraph">A software build pipeline is the collection of processes and tools used to manage, build, test, and deploy an application in a structured, repeatable way. In a traditional embedded workflow, a developer writes code, manually tests it, and produces a firmware image that is manually flashed to the target device. This approach works at small scale, but it does not scale gracefully as team size or codebase complexity grows.</p>



<p class="wp-block-paragraph">A modern build pipeline replaces manual, error-prone steps with automation. The core benefits include:</p>



<ul class="wp-block-list">
<li><strong>Improved software quality</strong> through consistent, automated checks at every commit</li>
<li><strong>Reduced debugging time</strong> by catching defects early, before they compound</li>
<li><strong>Lower project costs</strong> by reducing rework and late-stage bug discovery</li>
<li><strong>Better deadline predictability</strong> through continuous visibility into code health</li>
<li><strong>Simplified deployment</strong> via automated, gated firmware delivery</li>
</ul>



<h2 class="wp-block-heading">The Four Stages of a Modern Embedded Build Pipeline</h2>



<p class="wp-block-paragraph">A practical embedded CI/CD pipeline can be broken down into four sequential stages. The first stage is triggered manually by the developer; the remaining three can be fully automated.</p>



<h3 class="wp-block-heading">Stage 1: Commit (Manual Trigger)</h3>



<p class="wp-block-paragraph">The developer commits source code to a version control repository. This commit is the event that triggers all downstream automation. The quality of the pipeline depends heavily on how frequently developers commit. Small, frequent commits — ideally at least once per day — provide faster feedback loops and make it far easier to isolate the cause of a build or test failure.</p>



<h3 class="wp-block-heading">Stage 2: Build and Analysis (Automated)</h3>



<p class="wp-block-paragraph">Once a commit lands, the CI server picks it up and triggers a full build of the firmware. This stage should also run static code analysis tools that examine the source for common defects, coding standard violations, and security vulnerabilities without executing the code. Both the compiler and static analysis tools should be invokable from the command line or expose plugins compatible with your CI server so that these steps require no human intervention.</p>



<h3 class="wp-block-heading">Stage 3: Test and Reporting (Automated)</h3>



<p class="wp-block-paragraph">After a successful build, the pipeline runs automated tests and generates reports. These tests may run on a host-based simulator, an emulator, or actual target hardware depending on the maturity of the test infrastructure. Results — including pass/fail status, code coverage metrics, and any warnings from the analysis stage — are reported back to the developer. If anything fails at this stage, the pipeline stops and no deployment occurs. The developer is notified and the cycle restarts with a new commit after fixes are applied.</p>



<h3 class="wp-block-heading">Stage 4: Deployment (Automated or Manual)</h3>



<p class="wp-block-paragraph">Only firmware that has passed all build, analysis, and test gates proceeds to deployment. Depending on the product and risk tolerance, deployment can be fully automated — pushing firmware to devices in the field via OTA (over-the-air) update mechanisms — or it can require a manual approval step before release. Either approach is valid; what matters is that the gate between test and deployment is enforced by the pipeline, not by human memory.</p>



<h2 class="wp-block-heading">Building the Pipeline Incrementally</h2>



<p class="wp-block-paragraph">Setting up a full embedded CI/CD pipeline is not something that happens overnight. It requires research, tooling decisions, implementation work, and team training. The practical approach is to add each stage incrementally, making each one solid before moving on to the next.</p>



<h3 class="wp-block-heading">Step 1: Establish Robust Version Control Practices</h3>



<p class="wp-block-paragraph">Most embedded teams now use some form of version control, which is a meaningful improvement from even a few years ago. However, committing code once a week — or less — is still common and largely defeats the purpose. The pipeline can only provide timely feedback if commits are frequent. Aim for at least one commit per developer per day, ideally more. This discipline also forces developers to break work into smaller, reviewable increments, which itself improves code quality.</p>



<h3 class="wp-block-heading">Step 2: Stand Up a Continuous Integration Server</h3>



<p class="wp-block-paragraph">A CI server is the orchestration engine of the pipeline. It monitors the repository for new commits, triggers builds, runs analysis and tests, and reports results. Jenkins is one of the most widely adopted CI servers and has a large ecosystem of plugins relevant to embedded development, including support for various compilers and test frameworks. Other options exist and the right choice depends on your existing toolchain and infrastructure. What matters is that the CI server can be configured to execute your build and test steps automatically without manual intervention.</p>



<h3 class="wp-block-heading">Step 3: Automate the Compiler and Add Static Analysis</h3>



<p class="wp-block-paragraph">Your compiler must be executable from the command line so the CI server can invoke it without a GUI. Most professional embedded compilers support this, but verify your toolchain does before committing to a CI approach. If your team does not yet use a static code analysis tool, this is an appropriate point to evaluate and adopt one. Static analysis catches entire classes of defects — null pointer dereferences, buffer overflows, uninitialized variables, MISRA violations — that compiler warnings alone will not surface. Integrating static analysis into the automated pipeline means every commit is checked, not just when a developer remembers to run the tool manually.</p>



<h3 class="wp-block-heading">Step 4: Implement a Test Harness</h3>



<p class="wp-block-paragraph">Automated testing is the most valuable and also the most challenging stage to add to an embedded pipeline. Unlike application software, embedded code often has tight hardware dependencies that complicate host-based unit testing. Hardware Abstraction Layers (HALs) and dependency injection patterns can help decouple business logic from hardware-specific code, making more of the codebase testable without physical hardware.</p>



<p class="wp-block-paragraph">Test harnesses for embedded C/C++ such as Unity, CppUTest, or GoogleTest can run unit tests on the host machine as part of the CI pipeline. For integration tests that require hardware, Hardware-in-the-Loop (HIL) test rigs can automate execution against real targets. Regardless of approach, the most important principle is to build tests alongside the code — not after the fact. Test-Driven Development (TDD) is one effective methodology for achieving this. Automated tests that cover only a fraction of the codebase can create false confidence; invest in meaningful coverage from the beginning.</p>



<h2 class="wp-block-heading">Key Tools to Consider</h2>



<figure class="wp-block-table"><table><thead><tr><th>Pipeline Stage</th><th>Common Tool Examples</th></tr></thead><tbody><tr><td>Version Control</td><td>Git (with GitHub, GitLab, or Bitbucket)</td></tr><tr><td>CI Server</td><td>Jenkins, GitLab CI, GitHub Actions</td></tr><tr><td>Static Analysis</td><td>PC-lint, Polyspace, Cppcheck, MISRA checkers</td></tr><tr><td>Unit Test Frameworks</td><td>Unity, CppUTest, GoogleTest</td></tr><tr><td>Build Systems</td><td>Make, CMake, SCons</td></tr><tr><td>Deployment / OTA</td><td>Custom scripts, Mender, balena</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><em>Note: Tool selection should be driven by your target architecture, compiler ecosystem, and team familiarity. The table above lists representative options, not exhaustive recommendations.</em></p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">Modernizing the embedded software build pipeline is a meaningful investment, but one that pays dividends throughout the entire product lifecycle. Faster feedback, earlier defect detection, and automated deployments reduce the unpredictability that plagues so many embedded development projects. The key is not to attempt the full pipeline transformation in a single sprint. Start with solid version control practices, add a CI server, automate the build and analysis stages, then gradually introduce automated testing. Each stage you add compounds the benefits of the previous one. Over time, you end up with a pipeline that gives your team continuous visibility into software health and the confidence to deploy firmware reliably.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/developing-an-embedded-software-build-pipeline/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Java Build Tools: Ant vs. Maven vs. Gradle</title>
		<link>https://www.bestdevops.com/java-build-tools-ant-vs-maven-vs-gradle/</link>
					<comments>https://www.bestdevops.com/java-build-tools-ant-vs-maven-vs-gradle/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Mon, 01 May 2017 08:48:51 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Ant or Maven or Gradle]]></category>
		<category><![CDATA[Build Tools]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java Build Tools]]></category>
		<category><![CDATA[Maven]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1426</guid>

					<description><![CDATA[Source &#8211; 126kr.com For anything but the most trivial applications, compiling Java from the command line is an exercise in masochism. [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Source &#8211; 126kr.com</p>
<p>For anything but the most trivial applications, compiling Java from the command line is an exercise in masochism. The difficulty including dependencies and making executable .<span id="IL_AD2" class="IL_AD">jar files</span>is why build tools were created.</p>
<p>For this example, we will be compiling this trivial application:</p>
<div>
<div id="highlighter_823465" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">package com.example.iscream;</code></div>
<div class="line number2 index1 alt1"></div>
<div class="line number3 index2 alt2"><code class="html plain">import com.example.iscream.service.DailySpecialService;</code></div>
<div class="line number4 index3 alt1"><code class="html plain">import java.util.List;</code></div>
<div class="line number5 index4 alt2"></div>
<div class="line number6 index5 alt1"><code class="html plain">public class Application {</code></div>
<div class="line number7 index6 alt2"><code class="html spaces">    </code><code class="html plain">public static void main(String[] args) {</code></div>
<div class="line number8 index7 alt1"><code class="html spaces">        </code><code class="html plain">System.out.println("Starting store!\n\n==============\n");</code></div>
<div class="line number9 index8 alt2"></div>
<div class="line number10 index9 alt1"><code class="html spaces">        </code><code class="html plain">DailySpecialService dailySpecialService = new DailySpecialService();</code></div>
<div class="line number11 index10 alt2"><code class="html spaces">        </code><code class="html plain">List&lt;</code><code class="html keyword">String</code><code class="html plain">&gt; dailySpecials = dailySpecialService.getSpecials();</code></div>
<div class="line number12 index11 alt1"></div>
<div class="line number13 index12 alt2"><code class="html spaces">        </code><code class="html plain">System.out.println("Today's specials are:");</code></div>
<div class="line number14 index13 alt1"><code class="html spaces">        </code><code class="html plain">dailySpecials.forEach(s -&gt; System.out.println(" - " + s));</code></div>
<div class="line number15 index14 alt2"><code class="html spaces">    </code><code class="html plain">}</code></div>
<div class="line number16 index15 alt1"><code class="html plain">}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div>
<div id="highlighter_973604" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">package com.example.iscream.service;</code></div>
<div class="line number2 index1 alt1"></div>
<div class="line number3 index2 alt2"><code class="html plain">import com.google.common.collect.Lists;</code></div>
<div class="line number4 index3 alt1"><code class="html plain">import java.util.List;</code></div>
<div class="line number5 index4 alt2"></div>
<div class="line number6 index5 alt1"><code class="html plain">public class DailySpecialService {</code></div>
<div class="line number7 index6 alt2"></div>
<div class="line number8 index7 alt1"><code class="html spaces">    </code><code class="html plain">public List&lt;</code><code class="html keyword">String</code><code class="html plain">&gt; getSpecials() {</code></div>
<div class="line number9 index8 alt2"><code class="html spaces">        </code><code class="html plain">return Lists.newArrayList("Salty Caramel", "Coconut Chip", "Maui Mango");</code></div>
<div class="line number10 index9 alt1"><code class="html spaces">    </code><code class="html plain">}</code></div>
<div class="line number11 index10 alt2"><code class="html plain">}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h3>Ant</h3>
<p>The program <code>make</code> has been used for over forty years to compile <span id="IL_AD1" class="IL_AD">source code</span> into applications. As such, it was the natural choice in Java’s early years. Unfortunately, a lot of the assumptions and conventions with C programs don’t translate well to the Java ecosystem. To make (har) building the Java Tomcat application easier, James Duncan Davidson wrote Ant. Soon, other open source projects started using Ant, and from there it quickly spread throughout the community.</p>
<h4>Build files</h4>
<p>Ant build files are written in XML and are called <code>build.xml</code> by convention. I know even the word “XML” makes some people shudder, but in small doses it isn’t too painful. I promise. Ant calls the different phases of the build process “targets”. Targets that are defined in the build file can then be invoked using the <code>ant TARGET</code> command where <code>TARGET</code> is the name of the target.</p>
<p>Here’s the complete build file with the defined targets:</p>
<div>
<div id="highlighter_725486" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
<div class="line number24 index23 alt1">24</div>
<div class="line number25 index24 alt2">25</div>
<div class="line number26 index25 alt1">26</div>
<div class="line number27 index26 alt2">27</div>
<div class="line number28 index27 alt1">28</div>
<div class="line number29 index28 alt2">29</div>
<div class="line number30 index29 alt1">30</div>
<div class="line number31 index30 alt2">31</div>
<div class="line number32 index31 alt1">32</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">&lt;</code><code class="html keyword">project</code><code class="html plain">&gt;</code></div>
<div class="line number2 index1 alt1"></div>
<div class="line number3 index2 alt2"><code class="html spaces">    </code><code class="html plain">&lt;</code><code class="html keyword">path</code> <code class="html color1">id</code><code class="html plain">=</code><code class="html string">"classpath"</code><code class="html plain">&gt;</code></div>
<div class="line number4 index3 alt1"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">fileset</code> <code class="html color1">dir</code><code class="html plain">=</code><code class="html string">"lib"</code> <code class="html color1">includes</code><code class="html plain">=</code><code class="html string">"**/*.jar"</code><code class="html plain">/&gt;</code></div>
<div class="line number5 index4 alt2"><code class="html spaces">    </code><code class="html plain">&lt;/</code><code class="html keyword">path</code><code class="html plain">&gt;</code></div>
<div class="line number6 index5 alt1"></div>
<div class="line number7 index6 alt2"><code class="html spaces">    </code><code class="html plain">&lt;</code><code class="html keyword">target</code> <code class="html color1">name</code><code class="html plain">=</code><code class="html string">"clean"</code><code class="html plain">&gt;</code></div>
<div class="line number8 index7 alt1"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">delete</code> <code class="html color1">dir</code><code class="html plain">=</code><code class="html string">"build"</code><code class="html plain">/&gt;</code></div>
<div class="line number9 index8 alt2"><code class="html spaces">    </code><code class="html plain">&lt;/</code><code class="html keyword">target</code><code class="html plain">&gt;</code></div>
<div class="line number10 index9 alt1"></div>
<div class="line number11 index10 alt2"><code class="html spaces">    </code><code class="html plain">&lt;</code><code class="html keyword">target</code> <code class="html color1">name</code><code class="html plain">=</code><code class="html string">"compile"</code><code class="html plain">&gt;</code></div>
<div class="line number12 index11 alt1"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">mkdir</code> <code class="html color1">dir</code><code class="html plain">=</code><code class="html string">"build/classes"</code><code class="html plain">/&gt;</code></div>
<div class="line number13 index12 alt2"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">javac</code> <code class="html color1">srcdir</code><code class="html plain">=</code><code class="html string">"src/main/java"</code></div>
<div class="line number14 index13 alt1"><code class="html spaces">               </code><code class="html color1">destdir</code><code class="html plain">=</code><code class="html string">"build/classes"</code></div>
<div class="line number15 index14 alt2"><code class="html spaces">               </code><code class="html color1">classpathref</code><code class="html plain">=</code><code class="html string">"classpath"</code><code class="html plain">/&gt;</code></div>
<div class="line number16 index15 alt1"><code class="html spaces">    </code><code class="html plain">&lt;/</code><code class="html keyword">target</code><code class="html plain">&gt;</code></div>
<div class="line number17 index16 alt2"></div>
<div class="line number18 index17 alt1"><code class="html spaces">    </code><code class="html plain">&lt;</code><code class="html keyword">target</code> <code class="html color1">name</code><code class="html plain">=</code><code class="html string">"jar"</code><code class="html plain">&gt;</code></div>
<div class="line number19 index18 alt2"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">mkdir</code> <code class="html color1">dir</code><code class="html plain">=</code><code class="html string">"build/jar"</code><code class="html plain">/&gt;</code></div>
<div class="line number20 index19 alt1"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">jar</code> <code class="html color1">destfile</code><code class="html plain">=</code><code class="html string">"build/jar/IScream.jar"</code> <code class="html color1">basedir</code><code class="html plain">=</code><code class="html string">"build/classes"</code><code class="html plain">/&gt;</code></div>
<div class="line number21 index20 alt2"><code class="html spaces">    </code><code class="html plain">&lt;/</code><code class="html keyword">target</code><code class="html plain">&gt;</code></div>
<div class="line number22 index21 alt1"></div>
<div class="line number23 index22 alt2"><code class="html spaces">    </code><code class="html plain">&lt;</code><code class="html keyword">target</code> <code class="html color1">name</code><code class="html plain">=</code><code class="html string">"run"</code> <code class="html color1">depends</code><code class="html plain">=</code><code class="html string">"jar"</code><code class="html plain">&gt;</code></div>
<div class="line number24 index23 alt1"><code class="html spaces">        </code><code class="html plain">&lt;</code><code class="html keyword">java</code> <code class="html color1">fork</code><code class="html plain">=</code><code class="html string">"true"</code> <code class="html color1">classname</code><code class="html plain">=</code><code class="html string">"com.example.iscream.Application"</code><code class="html plain">&gt;</code></div>
<div class="line number25 index24 alt2"><code class="html spaces">            </code><code class="html plain">&lt;</code><code class="html keyword">classpath</code><code class="html plain">&gt;</code></div>
<div class="line number26 index25 alt1"><code class="html spaces">                </code><code class="html plain">&lt;</code><code class="html keyword">path</code> <code class="html color1">refid</code><code class="html plain">=</code><code class="html string">"classpath"</code><code class="html plain">/&gt;</code></div>
<div class="line number27 index26 alt2"><code class="html spaces">                </code><code class="html plain">&lt;</code><code class="html keyword">path</code> <code class="html color1">location</code><code class="html plain">=</code><code class="html string">"build/jar/IScream.jar"</code><code class="html plain">/&gt;</code></div>
<div class="line number28 index27 alt1"><code class="html spaces">            </code><code class="html plain">&lt;/</code><code class="html keyword">classpath</code><code class="html plain">&gt;</code></div>
<div class="line number29 index28 alt2"><code class="html spaces">        </code><code class="html plain">&lt;/</code><code class="html keyword">java</code><code class="html plain">&gt;</code></div>
<div class="line number30 index29 alt1"><code class="html spaces">    </code><code class="html plain">&lt;/</code><code class="html keyword">target</code><code class="html plain">&gt;</code></div>
<div class="line number31 index30 alt2"></div>
<div class="line number32 index31 alt1"><code class="html plain">&lt;/</code><code class="html keyword">project</code><code class="html plain">&gt;</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>With these targets defined, you may run <code>ant clean</code> , <code>ant compile</code> , <code>ant jar</code> , <code>ant run</code> to compile, build, and run the application we built.</p>
<p>Of course, the build file you’re likely to encounter in a real project is going to be much more complex than this example. Ant has dozens of built-in tasks , and it’s possible to define custom tasks too. A typical build might move around files, assemble documentation, run tests, publish build artifacts, etc. If you are lucky and are working on a well-maintained project, the build file should “just work”. If not, you may have to make tweaks for your specific computer. Keep an eye out for <code>.properties</code> files referenced by the build file that may contain configurable filepaths, environments, etc.</p>
<h4>Summary</h4>
<p>While setting up a build script takes some time up front, hopefully you can see the benefit of using one over passing commands manually to Java. Of course, Ant isn’t without its own problems. First, there are few enforced standards in an Ant script. This provides flexibility, but at the cost of every build file being entirely different. In the same way that knowing Java doesn’t mean you can jump into any codebase, knowing Ant doesn’t mean you can jump into any Ant file–you need to take time to understand it. Second, the imperative nature of Ant means build scripts can get very, very long. One example I found is over 2000 lines long ! Finally, we learned Ant has no built-in capability for dependency management, although it can be supplemented with Ivy. These limitations along with some other build script annoyances led to the creation of Maven in the early 2000s.</p>
<h3>Maven</h3>
<p>Maven is really two tools in one: a dependency manager and a build tool. Like Ant it is XML-based, but unlike Ant, it outlines fairly rigid standards. Furthermore, Maven is declarative allowing you to define <em>what</em> your build should do and less about <em>how</em> to do it. These advantages make Maven appealing; build files are much more standard across projects and developers spend less time tailoring the files. As such, Maven has become somewhat of a de facto standard in the Java world.</p>
<h4>Maven Phases</h4>
<p>The most common build phases are included in Maven and can be executed by running <code>mvn PHASE</code> (where <code>PHASE</code> is the phase name). The most common phase you will invoke is <code>install</code>because it will fully build and test the project, then create a build artifact.</p>
<p>Although it isn’t actually a phase, the command <code>mvn clean</code> deserves a mention. Running that command will “clean” your local build directory (i.e. <code>/target</code> ), and remove compiled classes, resources, packages, etc. In theory, you should just be able to run <code>mvn <span id="IL_AD3" class="IL_AD">install</span></code> and your build directory will be updated automatically. However, it seems that enough developers (including myself) have been burned by this not working that we habitually run <code>mvn clean install</code> to force the project to build from scratch.</p>
<h4>Project Object Model (POM) Files</h4>
<p>Maven’s build files are called Project Object Model files, usually just abbreviated to POM, and are saved as <code>pom.xml</code> in the root directory of a project. In order for Maven to work out of the box, it’s important to follow this directory structure:</p>
<div>
<div id="highlighter_925346" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">.</code></div>
<div class="line number2 index1 alt1"><code class="html plain">├── pom.xml</code></div>
<div class="line number3 index2 alt2"><code class="html plain">└── src</code></div>
<div class="line number4 index3 alt1"><code class="html spaces">    </code><code class="html plain">├── main</code></div>
<div class="line number5 index4 alt2"><code class="html spaces">    </code><code class="html plain">│   ├── java</code></div>
<div class="line number6 index5 alt1"><code class="html spaces">    </code><code class="html plain">│   │    &lt;-- Your Java code goes here</code></div>
<div class="line number7 index6 alt2"><code class="html spaces">    </code><code class="html plain">│   ├── resources</code></div>
<div class="line number8 index7 alt1"><code class="html spaces">    </code><code class="html plain">│   │    &lt;-- Non-code files that your app/library needs</code></div>
<div class="line number9 index8 alt2"><code class="html spaces">    </code><code class="html plain">└── test</code></div>
<div class="line number10 index9 alt1"><code class="html spaces">        </code><code class="html plain">├── java</code></div>
<div class="line number11 index10 alt2"><code class="html spaces">        </code><code class="html plain">│    &lt;-- Java tests</code></div>
<div class="line number12 index11 alt1"><code class="html spaces">        </code><code class="html plain">├── resources</code></div>
<div class="line number13 index12 alt2"><code class="html spaces">        </code><code class="html plain">│    &lt;-- Non-code files that your tests need</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>As mentioned previously, Maven has dependency management built in. The easiest way to find the correct values are from the project&#8217;s website or the MVNRepository site. For our build, we also need to use one of Apache&#8217;s official plugins&#8211;the Shade plugin. This plugin is used to build fat <code>.jar</code> files.</p>
<p>Here&#8217;s the complete POM file:</p>
<div>
<div id="highlighter_375242" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
<div class="line number24 index23 alt1">24</div>
<div class="line number25 index24 alt2">25</div>
<div class="line number26 index25 alt1">26</div>
<div class="line number27 index26 alt2">27</div>
<div class="line number28 index27 alt1">28</div>
<div class="line number29 index28 alt2">29</div>
<div class="line number30 index29 alt1">30</div>
<div class="line number31 index30 alt2">31</div>
<div class="line number32 index31 alt1">32</div>
<div class="line number33 index32 alt2">33</div>
<div class="line number34 index33 alt1">34</div>
<div class="line number35 index34 alt2">35</div>
<div class="line number36 index35 alt1">36</div>
<div class="line number37 index36 alt2">37</div>
<div class="line number38 index37 alt1">38</div>
<div class="line number39 index38 alt2">39</div>
<div class="line number40 index39 alt1">40</div>
<div class="line number41 index40 alt2">41</div>
<div class="line number42 index41 alt1">42</div>
<div class="line number43 index42 alt2">43</div>
<div class="line number44 index43 alt1">44</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">&lt;?</code><code class="html keyword">xml</code> <code class="html color1">version</code><code class="html plain">=</code><code class="html string">"1.0"</code> <code class="html color1">encoding</code><code class="html plain">=</code><code class="html string">"UTF-8"</code><code class="html plain">?&gt;</code></div>
<div class="line number2 index1 alt1"><code class="html plain">&lt;</code><code class="html keyword">project</code> <code class="html color1">xmlns</code><code class="html plain">=</code><code class="html string">"http://maven.apache.org/POM/4.0.0"</code> <code class="html color1">xmlns:xsi</code><code class="html plain">=</code><code class="html string">"http://www.w3.org/2001/XMLSchema-instance"</code> <code class="html color1">xsi:schemaLocation</code><code class="html plain">=</code><code class="html string">"http://maven.apache.org/POM/4.0.0                       https://maven.apache.org/xsd/maven-4.0.0.xsd"</code><code class="html plain">&gt;</code></div>
<div class="line number3 index2 alt2"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">modelVersion</code><code class="html plain">&gt;4.0.0&lt;/</code><code class="html keyword">modelVersion</code><code class="html plain">&gt;</code></div>
<div class="line number4 index3 alt1"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">groupId</code><code class="html plain">&gt;com.example&lt;/</code><code class="html keyword">groupId</code><code class="html plain">&gt;</code></div>
<div class="line number5 index4 alt2"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">artifactId</code><code class="html plain">&gt;iscream&lt;/</code><code class="html keyword">artifactId</code><code class="html plain">&gt;</code></div>
<div class="line number6 index5 alt1"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">version</code><code class="html plain">&gt;0.0.1-SNAPSHOT&lt;/</code><code class="html keyword">version</code><code class="html plain">&gt;</code></div>
<div class="line number7 index6 alt2"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">packaging</code><code class="html plain">&gt;jar&lt;/</code><code class="html keyword">packaging</code><code class="html plain">&gt;</code></div>
<div class="line number8 index7 alt1"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">properties</code><code class="html plain">&gt;</code></div>
<div class="line number9 index8 alt2"><code class="html spaces">      </code><code class="html plain">&lt;</code><code class="html keyword">maven.compiler.source</code><code class="html plain">&gt;1.8&lt;/</code><code class="html keyword">maven.compiler.source</code><code class="html plain">&gt;</code></div>
<div class="line number10 index9 alt1"><code class="html spaces">      </code><code class="html plain">&lt;</code><code class="html keyword">maven.compiler.target</code><code class="html plain">&gt;1.8&lt;/</code><code class="html keyword">maven.compiler.target</code><code class="html plain">&gt;</code></div>
<div class="line number11 index10 alt2"><code class="html spaces">      </code><code class="html plain">&lt;</code><code class="html keyword">project.build.sourceEncoding</code><code class="html plain">&gt;UTF-8&lt;/</code><code class="html keyword">project.build.sourceEncoding</code><code class="html plain">&gt;</code></div>
<div class="line number12 index11 alt1"><code class="html spaces">   </code><code class="html plain">&lt;/</code><code class="html keyword">properties</code><code class="html plain">&gt;</code></div>
<div class="line number13 index12 alt2"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">dependencies</code><code class="html plain">&gt;</code></div>
<div class="line number14 index13 alt1"><code class="html spaces">      </code><code class="html plain">&lt;</code><code class="html keyword">dependency</code><code class="html plain">&gt;</code></div>
<div class="line number15 index14 alt2"><code class="html spaces">         </code><code class="html plain">&lt;</code><code class="html keyword">groupId</code><code class="html plain">&gt;com.google.guava&lt;/</code><code class="html keyword">groupId</code><code class="html plain">&gt;</code></div>
<div class="line number16 index15 alt1"><code class="html spaces">         </code><code class="html plain">&lt;</code><code class="html keyword">artifactId</code><code class="html plain">&gt;guava&lt;/</code><code class="html keyword">artifactId</code><code class="html plain">&gt;</code></div>
<div class="line number17 index16 alt2"><code class="html spaces">         </code><code class="html plain">&lt;</code><code class="html keyword">version</code><code class="html plain">&gt;21.0&lt;/</code><code class="html keyword">version</code><code class="html plain">&gt;</code></div>
<div class="line number18 index17 alt1"><code class="html spaces">      </code><code class="html plain">&lt;/</code><code class="html keyword">dependency</code><code class="html plain">&gt;</code></div>
<div class="line number19 index18 alt2"><code class="html spaces">   </code><code class="html plain">&lt;/</code><code class="html keyword">dependencies</code><code class="html plain">&gt;</code></div>
<div class="line number20 index19 alt1"><code class="html spaces">   </code><code class="html plain">&lt;</code><code class="html keyword">build</code><code class="html plain">&gt;</code></div>
<div class="line number21 index20 alt2"><code class="html spaces">      </code><code class="html plain">&lt;</code><code class="html keyword">plugins</code><code class="html plain">&gt;</code></div>
<div class="line number22 index21 alt1"><code class="html spaces">         </code><code class="html plain">&lt;</code><code class="html keyword">plugin</code><code class="html plain">&gt;</code></div>
<div class="line number23 index22 alt2"><code class="html spaces">            </code><code class="html plain">&lt;</code><code class="html keyword">groupId</code><code class="html plain">&gt;org.apache.maven.plugins&lt;/</code><code class="html keyword">groupId</code><code class="html plain">&gt;</code></div>
<div class="line number24 index23 alt1"><code class="html spaces">            </code><code class="html plain">&lt;</code><code class="html keyword">artifactId</code><code class="html plain">&gt;maven-shade-plugin&lt;/</code><code class="html keyword">artifactId</code><code class="html plain">&gt;</code></div>
<div class="line number25 index24 alt2"><code class="html spaces">            </code><code class="html plain">&lt;</code><code class="html keyword">version</code><code class="html plain">&gt;2.3&lt;/</code><code class="html keyword">version</code><code class="html plain">&gt;</code></div>
<div class="line number26 index25 alt1"><code class="html spaces">            </code><code class="html plain">&lt;</code><code class="html keyword">executions</code><code class="html plain">&gt;</code></div>
<div class="line number27 index26 alt2"><code class="html spaces">               </code><code class="html plain">&lt;</code><code class="html keyword">execution</code><code class="html plain">&gt;</code></div>
<div class="line number28 index27 alt1"><code class="html spaces">                  </code><code class="html plain">&lt;</code><code class="html keyword">phase</code><code class="html plain">&gt;package&lt;/</code><code class="html keyword">phase</code><code class="html plain">&gt;</code></div>
<div class="line number29 index28 alt2"><code class="html spaces">                  </code><code class="html plain">&lt;</code><code class="html keyword">goals</code><code class="html plain">&gt;</code></div>
<div class="line number30 index29 alt1"><code class="html spaces">                     </code><code class="html plain">&lt;</code><code class="html keyword">goal</code><code class="html plain">&gt;shade&lt;/</code><code class="html keyword">goal</code><code class="html plain">&gt;</code></div>
<div class="line number31 index30 alt2"><code class="html spaces">                  </code><code class="html plain">&lt;/</code><code class="html keyword">goals</code><code class="html plain">&gt;</code></div>
<div class="line number32 index31 alt1"><code class="html spaces">                  </code><code class="html plain">&lt;</code><code class="html keyword">configuration</code><code class="html plain">&gt;</code></div>
<div class="line number33 index32 alt2"><code class="html spaces">                     </code><code class="html plain">&lt;</code><code class="html keyword">transformers</code><code class="html plain">&gt;</code></div>
<div class="line number34 index33 alt1"><code class="html spaces">                        </code><code class="html plain">&lt;</code><code class="html keyword">transformer</code> <code class="html color1">implementation</code><code class="html plain">=</code><code class="html string">"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"</code><code class="html plain">&gt;</code></div>
<div class="line number35 index34 alt2"><code class="html spaces">                           </code><code class="html plain">&lt;</code><code class="html keyword">mainClass</code><code class="html plain">&gt;com.example.iscream.Application&lt;/</code><code class="html keyword">mainClass</code><code class="html plain">&gt;</code></div>
<div class="line number36 index35 alt1"><code class="html spaces">                        </code><code class="html plain">&lt;/</code><code class="html keyword">transformer</code><code class="html plain">&gt;</code></div>
<div class="line number37 index36 alt2"><code class="html spaces">                     </code><code class="html plain">&lt;/</code><code class="html keyword">transformers</code><code class="html plain">&gt;</code></div>
<div class="line number38 index37 alt1"><code class="html spaces">                  </code><code class="html plain">&lt;/</code><code class="html keyword">configuration</code><code class="html plain">&gt;</code></div>
<div class="line number39 index38 alt2"><code class="html spaces">               </code><code class="html plain">&lt;/</code><code class="html keyword">execution</code><code class="html plain">&gt;</code></div>
<div class="line number40 index39 alt1"><code class="html spaces">            </code><code class="html plain">&lt;/</code><code class="html keyword">executions</code><code class="html plain">&gt;</code></div>
<div class="line number41 index40 alt2"><code class="html spaces">         </code><code class="html plain">&lt;/</code><code class="html keyword">plugin</code><code class="html plain">&gt;</code></div>
<div class="line number42 index41 alt1"><code class="html spaces">      </code><code class="html plain">&lt;/</code><code class="html keyword">plugins</code><code class="html plain">&gt;</code></div>
<div class="line number43 index42 alt2"><code class="html spaces">   </code><code class="html plain">&lt;/</code><code class="html keyword">build</code><code class="html plain">&gt;</code></div>
<div class="line number44 index43 alt1"><code class="html plain">&lt;/</code><code class="html keyword">project</code><code class="html plain">&gt;</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>At this point you can run <code>mvn package</code> and you will see the <code>iscream-0.0.1-SNAPSHOT.jar</code> file inside of the <code>target</code> folder. If you run <code>java -jar iscream-0.0.1-SNAPSHOT.jar</code> you can run the application.</p>
<h4>Summary</h4>
<p>Although Maven has made considerable strides in making builds easier, all Maven users have found themselves banging their head against the wall with a tricky Maven problem at one time or another. I&#8217;ve already mentioned some usability problems with plugins, but there&#8217;s also the problem of &#8220;The Maven Way&#8221;. Anytime a build deviates from what Maven expects, it can be difficult to put in a work-around. Many projects are &#8220;normal&#8230;except for that one weird thing we have to do&#8221;. And the more &#8220;weird things&#8221; in the build, the harder it can be to bend Maven to your will. Wouldn&#8217;t it be great if we could combine the flexibility of Ant with the features of Maven? That&#8217;s exactly what Gradle is trying to do.</p>
<h3>Gradle</h3>
<p>The first thing you will notice about a Gradle build script is that it is not XML! In fact, Gradle uses a domain specific language (DSL) based on Groovy, which is another programming language that can run on the JVM.</p>
<p>The DSL defines both the core parts of the build file and specific build steps called &#8220;tasks&#8221;. It is also extensible making it very easy to define your own tasks. And of course, Gradle also has a rich third-party plugin library. Let&#8217;s dive in.</p>
<h4>Build files</h4>
<p>Gradle build files are appropriately named <code>build.gradle</code> and start out by configuring the build. For our project we need to take advantage of a fat jar plugin, so we will add the Shadow plugin to the build script configuration.</p>
<p>In order for Gradle to download the plugin, it has to look in a repository, which is an index for artifacts. Some repositories are known to Gradle and can be referred to simply as<code>mavenCentral()</code> or <code>jcenter()</code> . The Gradle team decided to not reinvent the wheel when it comes to repositories and instead relies on the existing Maven and Ivy dependency ecosystems.</p>
<h4>Tasks</h4>
<p>Finally after Ant&#8217;s obscure &#8220;target&#8221; and Maven&#8217;s confusing &#8220;phase&#8221;, Gradle gave a reasonable name to their build steps: &#8220;tasks&#8221;. We use Gradle&#8217;s <code>apply</code> to give access to certain tasks. (The<code>java</code> plugin is built in to Gradle which is why we did not need to declare it in the build&#8217;s dependencies.)</p>
<p>The <code>java</code> plugin will give you common tasks such as <code>clean</code> , <code>compileJava</code> , <code>test</code> , etc. The<code>shadow</code> plugin will give you the <code>shadowJar</code> task which builds a fat jar. To see a complete list of the available tasks, you can run <code>gradle -q tasks</code> .</p>
<h4>Dependency Management</h4>
<p>We&#8217;ve already discussed how a build script can rely on a plugin dependency, likewise the build script can define the dependencies for your project. Here&#8217;s the complete build file:</p>
<div>
<div id="highlighter_560705" class="syntaxhighlighter html">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
<div class="line number24 index23 alt1">24</div>
<div class="line number25 index24 alt2">25</div>
<div class="line number26 index25 alt1">26</div>
<div class="line number27 index26 alt2">27</div>
<div class="line number28 index27 alt1">28</div>
<div class="line number29 index28 alt2">29</div>
<div class="line number30 index29 alt1">30</div>
<div class="line number31 index30 alt2">31</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="html plain">buildscript {</code></div>
<div class="line number2 index1 alt1"><code class="html spaces">    </code><code class="html plain">repositories {</code></div>
<div class="line number3 index2 alt2"><code class="html spaces">        </code><code class="html plain">jcenter()</code></div>
<div class="line number4 index3 alt1"><code class="html spaces">    </code><code class="html plain">}</code></div>
<div class="line number5 index4 alt2"><code class="html spaces">    </code><code class="html plain">dependencies {</code></div>
<div class="line number6 index5 alt1"><code class="html spaces">        </code><code class="html plain">classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4'</code></div>
<div class="line number7 index6 alt2"><code class="html spaces">    </code><code class="html plain">}</code></div>
<div class="line number8 index7 alt1"><code class="html plain">}</code></div>
<div class="line number9 index8 alt2"></div>
<div class="line number10 index9 alt1"><code class="html plain">apply plugin: 'java'</code></div>
<div class="line number11 index10 alt2"><code class="html plain">apply plugin: 'com.github.johnrengelman.shadow'</code></div>
<div class="line number12 index11 alt1"></div>
<div class="line number13 index12 alt2"><code class="html plain">group = 'com.example'</code></div>
<div class="line number14 index13 alt1"><code class="html plain">version = '0.0.1-SNAPSHOT'</code></div>
<div class="line number15 index14 alt2"><code class="html plain">sourceCompatibility = 1.8</code></div>
<div class="line number16 index15 alt1"><code class="html plain">targetCompatibility = 1.8</code></div>
<div class="line number17 index16 alt2"></div>
<div class="line number18 index17 alt1"><code class="html plain">repositories {</code></div>
<div class="line number19 index18 alt2"><code class="html spaces">    </code><code class="html plain">mavenCentral()</code></div>
<div class="line number20 index19 alt1"><code class="html plain">}</code></div>
<div class="line number21 index20 alt2"></div>
<div class="line number22 index21 alt1"><code class="html plain">dependencies {</code></div>
<div class="line number23 index22 alt2"><code class="html spaces">    </code><code class="html plain">compile group: 'com.google.guava', name: 'guava', version: '21.0'</code></div>
<div class="line number24 index23 alt1"><code class="html plain">}</code></div>
<div class="line number25 index24 alt2"></div>
<div class="line number26 index25 alt1"><code class="html plain">shadowJar {</code></div>
<div class="line number27 index26 alt2"><code class="html spaces">    </code><code class="html plain">baseName = 'iscream'</code></div>
<div class="line number28 index27 alt1"><code class="html spaces">    </code><code class="html plain">manifest {</code></div>
<div class="line number29 index28 alt2"><code class="html spaces">        </code><code class="html plain">attributes 'Main-Class': 'com.example.iscream.Application'</code></div>
<div class="line number30 index29 alt1"><code class="html spaces">    </code><code class="html plain">}</code></div>
<div class="line number31 index30 alt2"><code class="html plain">}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Now that the build knows how to find the project&#8217;s dependencies, we can run <code>gradle shawdowJar</code> to create a fat jar that includes the Guava dependency. After it completes, you should see <code>/build/lib/iscream-0.0.1-SNAPSHOT-all.jar</code> , which can be ran in the usual way (<code>java -jar ...</code> ).</p>
<h4>Summary</h4>
<p>Gradle brings a lot of flexibility and power to the Java build ecosystem. Of course, there is always some danger with highly customizable tools&#8211;suddenly you have to be aware of code quality in your build file. This is not necessarily bad, but worth considering when evaluating how your team will use the tool. Furthermore, much of Gradle&#8217;s power comes from third-party plugins. And since it is relatively new, it still sometimes feels like you are using a bunch of plugins developed by SomeRandomPerson. You may find yourself comparing three plugins that ostensibly do the same thing, each have a few dozen GitHub stars, and little documentation to boot. Despite these downsides, Gradle is gaining popularity and is particularly appealing to developers who like to have more control over their builds.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/java-build-tools-ant-vs-maven-vs-gradle/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Seven Ways the Mature Docker Container Architecture Changes the Game</title>
		<link>https://www.bestdevops.com/seven-ways-the-mature-docker-container-architecture-changes-the-game/</link>
					<comments>https://www.bestdevops.com/seven-ways-the-mature-docker-container-architecture-changes-the-game/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Fri, 31 Mar 2017 16:31:35 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Best Practices]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Container architecture]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker architecture]]></category>
		<category><![CDATA[Docker container architecture]]></category>
		<category><![CDATA[Software Developement]]></category>
		<category><![CDATA[Swarm]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1100</guid>

					<description><![CDATA[Docker container architecture has evolved well beyond a single host and image. Learn the seven key decisions—hardware, OS, cloud vs. on-premises, orchestration, registries, security, and monitoring—that define a production-ready container stack.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on a topic originally covered by TechTarget. The explanation below is an independent technical summary of Docker container architecture decisions.</em></p>



<h2 class="wp-block-heading">What Is a Container Architecture?</h2>



<p class="wp-block-paragraph">A container architecture is the full set of hardware, software, and infrastructure components required to reliably host and operate applications inside containers at scale. It is not simply a matter of installing Docker and launching a container image.</p>



<p class="wp-block-paragraph">Running a single container is straightforward: you need a host operating system, a container image, and the Docker runtime. There is very little architectural decision-making involved. Production environments are a different story. You need high availability across multiple containers and physical nodes, automated lifecycle management, networking, storage, security controls, and observability. The sum of the choices you make to address those needs is your container architecture.</p>



<h2 class="wp-block-heading">How Docker Container Architecture Has Evolved</h2>



<p class="wp-block-paragraph">In Docker&#8217;s early days the ecosystem was small and the architecture choices were limited: a Linux host, an orchestrator, and a container image registry covered most use cases. As Docker matured and the surrounding ecosystem expanded, teams gained far more options—and far more decisions to make. The following seven dimensions capture the most consequential architectural choices in a modern Docker deployment.</p>



<h2 class="wp-block-heading">1. Hardware Options: VMs, Bare Metal, or System Containers</h2>



<p class="wp-block-paragraph">The physical or virtual foundation your containers run on shapes performance, portability, and operational complexity.</p>



<ul class="wp-block-list">
<li><strong>Virtual machines (VMs):</strong> Hosting Docker on VMs offers operational flexibility. VM images can be snapshotted, moved, and restored easily, which simplifies disaster recovery and infrastructure management. The trade-off is an additional hypervisor layer that adds latency and resource overhead.</li>
<li><strong>Bare-metal servers:</strong> Containers—unlike VMs—are not virtualized, so they can access host hardware directly. Bare-metal deployments eliminate the hypervisor overhead, delivering maximum CPU, memory, and I/O throughput. The trade-off is reduced portability and more complex hardware management.</li>
<li><strong>System container platforms (e.g., OpenVZ, LXD):</strong> These platforms aim to combine the flexibility of VMs with the performance density of containers. They represent a middle path worth evaluating for workloads that need strong isolation without full hardware virtualization overhead.</li>
</ul>



<h2 class="wp-block-heading">2. Host Operating System</h2>



<p class="wp-block-paragraph">Linux has been Docker&#8217;s native home since its inception, and the majority of production Docker deployments still run on Linux distributions such as Ubuntu, CentOS, RHEL, and CoreOS (now Fedora CoreOS).</p>



<p class="wp-block-paragraph">Docker announced official support for Windows Server 2016 in late 2016, enabling Windows containers alongside Linux containers on the same host when using Windows Subsystem for Linux 2 (WSL 2) in later iterations. Windows container support has grown since then, but Linux remains the dominant and more battle-tested choice for production container workloads. Your host OS selection should be driven by your application runtime requirements and your team&#8217;s operational expertise.</p>



<h2 class="wp-block-heading">3. Cloud vs. On-Premises Deployment</h2>



<p class="wp-block-paragraph">Container workloads can run on public cloud infrastructure, private on-premises infrastructure, or a hybrid of both.</p>



<ul class="wp-block-list">
<li><strong>Containers as a Service (CaaS):</strong> Managed platforms such as Amazon Elastic Container Service (ECS), Azure Container Instances, and Google Kubernetes Engine (GKE) abstract away cluster management, making it faster to get containers into production. The cost is reduced control over the underlying infrastructure and potential compliance constraints.</li>
<li><strong>Self-managed cloud VMs:</strong> Deploying Docker on cloud virtual servers (e.g., EC2 or Azure VMs) gives more control than a managed CaaS offering while still benefiting from cloud elasticity.</li>
<li><strong>On-premises:</strong> Running containers on hardware you own and operate maximizes control, supports strict data-residency requirements, and avoids cloud egress costs. It also demands more operational investment.</li>
</ul>



<p class="wp-block-paragraph">Compliance requirements—such as HIPAA, PCI-DSS, or GDPR—should heavily influence where you run containers and which managed services you use.</p>



<h2 class="wp-block-heading">4. Container Orchestration</h2>



<p class="wp-block-paragraph">Any production container cluster requires an orchestrator to schedule workloads, manage scaling, handle failure recovery, and coordinate networking. The three historically dominant orchestrators are:</p>



<ul class="wp-block-list">
<li><strong>Kubernetes:</strong> The de facto industry standard for container orchestration. It provides a rich API, a large ecosystem of extensions, and is supported by every major cloud provider.</li>
<li><strong>Docker Swarm:</strong> Integrated directly into the Docker Engine. Swarm is simpler to configure than Kubernetes and is suitable for smaller clusters or teams that want to minimize operational complexity.</li>
<li><strong>Apache Mesos / DC/OS:</strong> Designed for very large-scale, mixed workload clusters. Less common for pure container-only environments today.</li>
</ul>



<p class="wp-block-paragraph">Your choice of orchestrator may be constrained by your CaaS platform. For example, managed Kubernetes services lock you into the Kubernetes API, while some enterprise platforms bundle their own supported orchestrator. Factor orchestrator compatibility into your platform selection early.</p>



<h2 class="wp-block-heading">5. Image Registry</h2>



<p class="wp-block-paragraph">Container images must be stored somewhere accessible to your build pipelines and container hosts. Your registry strategy affects security, latency, and compliance.</p>



<ul class="wp-block-list">
<li><strong>Public registries (e.g., Docker Hub):</strong> Convenient for open source base images and public distribution. Not suitable for proprietary application images without private repository features.</li>
<li><strong>Cloud-hosted private registries:</strong> Amazon Elastic Container Registry (ECR), Azure Container Registry (ACR), and Google Artifact Registry offer private, managed registries with IAM-based access control and geographic proximity to cloud-hosted clusters.</li>
<li><strong>Self-hosted registries:</strong> The open source Docker Registry, VMware Harbor, and the registries bundled into platforms like Red Hat OpenShift provide maximum control over image storage, access policies, and data residency.</li>
</ul>



<h2 class="wp-block-heading">6. Security Tooling</h2>



<p class="wp-block-paragraph">Security must be addressed at every layer of the container stack, not bolted on as an afterthought. Key security controls include:</p>



<ul class="wp-block-list">
<li><strong>Image scanning:</strong> Tools such as Clair (open source), Trivy, and Snyk analyze container images for known CVEs before they reach production registries or running clusters.</li>
<li><strong>Host hardening:</strong> Security-Enhanced Linux (SELinux) and AppArmor provide mandatory access controls that restrict what the Docker daemon and container processes can do on the host.</li>
<li><strong>Runtime security:</strong> Commercial platforms such as Aqua Security and Sysdig Falco monitor container behavior at runtime, detecting anomalous activity and enforcing policies.</li>
<li><strong>Network policies:</strong> Kubernetes Network Policies (enforced by a compatible CNI plugin such as Calico or Cilium) restrict which pods can communicate with each other, reducing lateral movement risk.</li>
<li><strong>Secrets management:</strong> Avoid embedding secrets in images. Use tools such as HashiCorp Vault, Kubernetes Secrets (ideally with encryption at rest), or cloud-native secret managers.</li>
</ul>



<h2 class="wp-block-heading">7. Monitoring and Log Aggregation</h2>



<p class="wp-block-paragraph">Observability is non-negotiable in production. Container workloads are ephemeral and distributed, which means traditional log-and-monitor approaches must be adapted.</p>



<ul class="wp-block-list">
<li><strong>Metrics collection:</strong> Prometheus is the open source standard for scraping and storing container and cluster metrics. It integrates natively with Kubernetes and is widely supported by exporters for virtually every component in a container stack.</li>
<li><strong>Visualization:</strong> Grafana provides dashboards on top of Prometheus and other data sources, giving teams visibility into cluster health, resource utilization, and application performance.</li>
<li><strong>Log aggregation:</strong> The EFK stack (Elasticsearch, Fluentd, Kibana) or the more modern Loki stack (Grafana Loki + Promtail) collects, indexes, and queries logs from all containers centrally.</li>
<li><strong>Cloud-native options:</strong> AWS CloudWatch, Azure Monitor, and Google Cloud Operations Suite offer integrated monitoring and logging for containers running on their respective platforms, reducing the operational overhead of self-managing observability infrastructure.</li>
<li><strong>Container-aware APM:</strong> Vendors such as New Relic, Datadog, and Dynatrace offer agents and integrations that provide full-stack visibility from the container runtime up through application traces.</li>
</ul>



<h2 class="wp-block-heading">Putting It All Together</h2>



<p class="wp-block-paragraph">A mature Docker container architecture is not a single product—it is a deliberate combination of hardware, operating system, deployment model, orchestrator, registry, security controls, and observability tooling. Each layer introduces trade-offs, and the right choices depend on your team&#8217;s size, compliance requirements, performance targets, and operational maturity.</p>



<p class="wp-block-paragraph">The container ecosystem continues to grow rapidly. Staying current with the tooling landscape—particularly in orchestration and security—is an ongoing investment, not a one-time decision. Treat your container architecture as a living system that evolves alongside your organization&#8217;s needs.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/seven-ways-the-mature-docker-container-architecture-changes-the-game/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How LinkedIn Built Bluepill to Solve iOS UI Test Parallelisation at Scale</title>
		<link>https://www.bestdevops.com/development-problem-solving-the-linkedin-way/</link>
					<comments>https://www.bestdevops.com/development-problem-solving-the-linkedin-way/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Wed, 25 Jan 2017 07:09:20 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[DevOps Best Practices]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Bluepill]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[Release]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=431</guid>

					<description><![CDATA[LinkedIn's 3×3 mobile release schedule demanded faster iOS testing than any off-the-shelf tool could deliver. Here's how their engineers built Bluepill, an open-source parallel iOS test runner, and what it means for teams facing the same bottleneck.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Original source: TechTarget / LinkedIn Engineering Blog (January 2017)</em></p>



<h2 class="wp-block-heading">The 3×3 Release Challenge</h2>



<p class="wp-block-paragraph">LinkedIn operates on what it calls a <strong>3×3 mobile release schedule</strong>: three releases per day, with a goal of never allowing code to sit uncommitted for more than three hours. At the scale LinkedIn operates, that cadence demands that every stage of the pipeline — including automated testing — runs fast, reliably, and without human bottlenecks.</p>



<p class="wp-block-paragraph">For most engineering teams, continuous integration pipelines already feel stretched when pushing one release per day. Tripling that frequency requires rethinking not just deployment, but every upstream gate, particularly automated UI testing on mobile.</p>



<h2 class="wp-block-heading">Where iOS UI Testing Became the Bottleneck</h2>



<p class="wp-block-paragraph">Automated iOS UI testing is notoriously slow. Running a full UI test suite sequentially on a single simulator can take far longer than the three-hour window LinkedIn had set for its release cycle. Off-the-shelf solutions available at the time could not adequately parallelize iOS simulator runs to fit within that window, and LinkedIn&#8217;s engineering team found themselves at a wall: without faster test execution, the 3×3 schedule simply was not achievable.</p>



<p class="wp-block-paragraph">The options were limited. Compromise the release cadence, accept reduced test coverage, or build something new.</p>



<h2 class="wp-block-heading">The Solution: Bluepill — An Open-Source Parallel iOS Test Runner</h2>



<p class="wp-block-paragraph">LinkedIn&#8217;s engineering team chose to build their own tool. Named <strong>Bluepill</strong> — a nod to <em>The Matrix</em> — it is an open-source iOS test runner designed to execute tests across multiple simulators in parallel. Key capabilities include:</p>



<ul class="wp-block-list">
  <li><strong>Parallel simulator execution:</strong> Bluepill spawns multiple iOS simulators simultaneously, distributing the test suite across them to cut overall wall-clock execution time.</li>
  <li><strong>Intelligent test packing:</strong> Tests are grouped into balanced batches so that simulators finish at roughly the same time, avoiding idle resources waiting on a slow final batch.</li>
  <li><strong>JUnit report output:</strong> After each run, Bluepill produces a standard JUnit XML report, making it straightforward to integrate with existing CI dashboards and reporting tools.</li>
</ul>



<p class="wp-block-paragraph">LinkedIn open-sourced Bluepill in January 2017. Full details are available on the <a href="https://engineering.linkedin.com/blog/2017/01/open-sourcing-bluepill--run-ios-tests-in-multiple-simulators">LinkedIn Engineering Blog</a>.</p>



<h2 class="wp-block-heading">How Long Did It Take to Build?</h2>



<p class="wp-block-paragraph">LinkedIn engineer Oscar Bonilla described the development timeline directly:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  <p>&#8220;The first commit happened on Aug. 12 and we had it working on the LinkedIn Continuous Integration system by Nov. 1. From there we continued to polish the project and address a few bugs. So in total it took about 10 weeks to build Bluepill and another 10 to refine it.&#8221;</p>
  <cite>— Oscar Bonilla, LinkedIn Engineering</cite>
</blockquote>



<p class="wp-block-paragraph">That is roughly five months from initial commit to a production-hardened open-source release — a reasonable timeline for a tool that reportedly saved LinkedIn thousands of developer hours.</p>



<h2 class="wp-block-heading">Lessons for DevOps and Mobile Engineering Teams</h2>



<p class="wp-block-paragraph">The Bluepill story illustrates several principles relevant to any team dealing with CI bottlenecks at scale:</p>



<ul class="wp-block-list">
  <li><strong>Identify the constraint precisely.</strong> LinkedIn did not try to speed up their entire pipeline at once. They identified iOS UI testing as the specific gate blocking their release cadence and focused engineering effort there.</li>
  <li><strong>Evaluate build-vs-buy honestly.</strong> Off-the-shelf tools failed to meet the requirement. Rather than forcing an inadequate tool into production, the team invested roughly ten weeks to build a fit-for-purpose solution.</li>
  <li><strong>Parallelisation is often the right lever for test speed.</strong> Distributing a test suite across multiple simulators or machines is frequently more practical than trying to make individual tests faster.</li>
  <li><strong>Open-sourcing internal tooling creates compounding value.</strong> By releasing Bluepill publicly, LinkedIn benefited from external contributions and bug reports while giving the broader iOS community a tool to address a common pain point.</li>
  <li><strong>Standard output formats matter.</strong> JUnit XML is a lingua franca for CI test results. Tools that produce it integrate immediately with Jenkins, CircleCI, GitHub Actions, and most other CI systems without custom parsing.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<p class="wp-block-paragraph">For the full technical details of Bluepill&#8217;s architecture and configuration options, see the original announcement on the <a href="https://engineering.linkedin.com/blog/2017/01/open-sourcing-bluepill--run-ios-tests-in-multiple-simulators">LinkedIn Engineering Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/development-problem-solving-the-linkedin-way/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automated Deployment Tools: Mitigating Human Error in DevOps</title>
		<link>https://www.bestdevops.com/automated-deployment-tools-mitigate-the-risk-of-human-error-in-devops/</link>
					<comments>https://www.bestdevops.com/automated-deployment-tools-mitigate-the-risk-of-human-error-in-devops/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Tue, 17 Jan 2017 05:23:31 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[DevOps Best Practices]]></category>
		<category><![CDATA[DevOps Process]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[Automated Deployment]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[Build automation]]></category>
		<category><![CDATA[Deployment Tools]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps toolchain]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=363</guid>

					<description><![CDATA[DevOps teams face a crowded, overlapping landscape of automated deployment tools. This guide maps the four core toolchain categories and offers practical selection criteria to help you build a CI/CD pipeline that reduces human error and scales with your organization.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on source material originally published on TechTarget (techtarget.com). The original post is dated January 2017; tool versions and vendor offerings may have changed since publication.</em></p>



<h2 class="wp-block-heading">The Problem With Too Many Choices</h2>



<p class="wp-block-paragraph">DevOps methodologies and continuous integration and delivery (CI/CD) practices have produced an explosion of automated deployment tools, each designed to streamline some part of the software delivery pipeline. The abundance of options is itself one of the biggest challenges teams face.</p>



<p class="wp-block-paragraph">IT and development organizations typically assemble complex toolchains that orchestrate the full application lifecycle—from code authoring and integration through automated testing to production deployment. Many of these tools originated to solve a narrow problem (automated system configuration, for example, or code merging), but have since expanded to cover adjacent stages of the CI/CD pipeline, blurring the lines between development tooling and infrastructure tooling.</p>



<p class="wp-block-paragraph">Feature creep, category overlap, and the absence of any industry-standard taxonomy for DevOps toolchains make tool selection genuinely difficult. Both proprietary and open-source technologies are widely used, and neither the categories nor the boundaries between them are stable. Despite this complexity, it is possible to identify broad groupings of tools that correspond to recognizable phases in the deployment process—and to apply concrete selection criteria once those groupings are understood.</p>



<h2 class="wp-block-heading">The Four Core Categories of the DevOps Toolchain</h2>



<p class="wp-block-paragraph">No tool fits neatly into a single box, but most automated deployment tools fall into one or more of the following four broad categories.</p>



<h3 class="wp-block-heading">1. Build Automation and Source Code Management</h3>



<p class="wp-block-paragraph">Source code management (SCM) and build automation tools let developers collaborate in parallel without creating conflicts or confusion in the codebase. Git has become the de facto standard version control system. Hosted Git services include:</p>



<ul class="wp-block-list">
<li><strong>GitHub</strong> – widely adopted, especially in open-source communities</li>
<li><strong>AWS CodeCommit</strong> – managed Git service integrated with the AWS ecosystem</li>
<li><strong>Google Cloud Source Repositories</strong> – Google&#8217;s hosted Git offering</li>
<li><strong>Microsoft Azure Repos</strong> (formerly Visual Studio Team Services) – integrated with the Azure DevOps suite</li>
<li><strong>Atlassian Bitbucket</strong> – popular in shops already using Jira or Confluence</li>
</ul>



<h3 class="wp-block-heading">2. Continuous Integration</h3>



<p class="wp-block-paragraph">CI tools automatically merge contributions from multiple developers into a shared source repository, then trigger build and test workflows on every change. Key options include:</p>



<ul class="wp-block-list">
<li><strong>Jenkins</strong> – one of the most widely deployed CI servers; highly extensible via plug-ins, enabling complex multi-stage pipelines covering build, test, and deployment</li>
<li><strong>CircleCI</strong> – cloud-native CI/CD with fast setup and YAML-based configuration</li>
<li><strong>Codeship</strong> – aimed at teams that want simplicity over deep customization</li>
<li><strong>TeamCity</strong> – JetBrains&#8217; CI server, well-suited to Java and .NET shops</li>
<li><strong>Travis CI</strong> – popular in open-source projects; integrates tightly with GitHub</li>
</ul>



<h3 class="wp-block-heading">3. Application Deployment and Configuration Management</h3>



<p class="wp-block-paragraph">Configuration management platforms handle system installation, activation, patching, updates, and eventual decommissioning. They often overlap with CI tooling and can be extended via plug-ins. Common choices include:</p>



<ul class="wp-block-list">
<li><strong>Ansible</strong> (Red Hat) – agentless, uses YAML playbooks; low barrier to entry</li>
<li><strong>Chef</strong> – uses a Ruby-based DSL for configuration &#8220;recipes&#8221;; mature ecosystem</li>
<li><strong>Puppet</strong> – declarative, model-based configuration; strong enterprise adoption</li>
<li><strong>SaltStack (Salt)</strong> – event-driven automation with fast execution over large fleets</li>
<li><strong>Capistrano</strong> – Ruby-based deployment tool, historically popular for web apps</li>
<li><strong>Fabric</strong> – Python library for remote shell commands and deployment tasks</li>
<li><strong>AWS OpsWorks</strong> – managed Chef and Puppet service within AWS</li>
<li><strong>Google Cloud Deployment Manager</strong> – declarative infrastructure management for GCP</li>
<li><strong>Microsoft Azure Automation</strong> – runbook-based automation using PowerShell or Python</li>
</ul>



<h3 class="wp-block-heading">4. Infrastructure Deployment (Infrastructure as Code)</h3>



<p class="wp-block-paragraph">Infrastructure as Code (IaC) tools treat server and network provisioning the same way developers treat application code: as versioned, reviewable, repeatable definitions. This approach enforces consistency between environments, reduces manual steps that introduce human error, and makes infrastructure auditable. Key tools include:</p>



<ul class="wp-block-list">
<li><strong>Terraform</strong> (HashiCorp) – cloud-agnostic IaC tool using HashiCorp Configuration Language (HCL); the production-scale successor to Vagrant</li>
<li><strong>Packer</strong> (HashiCorp) – automates the creation of machine and container images across multiple platforms</li>
<li><strong>AWS CloudFormation</strong> – native IaC for AWS using JSON or YAML templates</li>
<li><strong>Chef Habitat</strong> – application automation focused on containerized and cloud-native workloads</li>
</ul>



<p class="wp-block-paragraph">Note that tools from Category 3—Ansible, Chef, and Puppet in particular—can also perform infrastructure automation once the appropriate client-side agents or modules are installed in machine images, further blurring category boundaries.</p>



<h2 class="wp-block-heading">How to Select the Right Automated Deployment Tools</h2>



<p class="wp-block-paragraph">The following practical criteria can guide tool selection regardless of which specific products are on your shortlist.</p>



<h3 class="wp-block-heading">Think Holistically About the Entire CI/CD Stack</h3>



<p class="wp-block-paragraph">No single tool covers every stage of the pipeline. Plan for how tools will connect before committing to any one product. For example, a consultancy focused on agile delivery might combine Terraform for infrastructure orchestration, Ansible for provisioning and configuration, Jenkins for the CI code pipeline, and a Makefile as the glue that ties each stage together. Define the hand-off points between tools before you evaluate individual options.</p>



<h3 class="wp-block-heading">Match Tools to Your Language and Infrastructure Stack</h3>



<p class="wp-block-paragraph">Select tools that support the programming languages your developers already use, and that integrate cleanly with the infrastructure your operations team already manages. If your teams are already productive with Jenkins, evaluate whether it can serve additional teams or pipelines before introducing a competing CI tool.</p>



<h3 class="wp-block-heading">Factor in Team Expertise and Budget</h3>



<p class="wp-block-paragraph">Jenkins is powerful but has a steep configuration curve. If your DevOps budget is modest or your team lacks the bandwidth to learn a complex new tool, a simpler hosted option such as Codeship or TeamCity may deliver faster value. Operational simplicity is a legitimate selection criterion—especially for smaller teams.</p>



<h3 class="wp-block-heading">Evaluate Configuration Syntax and DSL Familiarity</h3>



<p class="wp-block-paragraph">Each tool uses a different syntax or domain-specific language (DSL):</p>



<ul class="wp-block-list">
<li><strong>Ansible</strong> uses YAML—structured and human-readable, but whitespace-sensitive and potentially unfamiliar to some team members</li>
<li><strong>Chef</strong> uses a Ruby-based DSL for its configuration recipes—an advantage for teams with Ruby experience</li>
<li><strong>Terraform</strong> uses HCL, which is declarative and relatively readable but requires learning its own resource model</li>
<li><strong>CloudFormation</strong> uses JSON or YAML, which is portable but can become verbose for large stacks</li>
</ul>



<p class="wp-block-paragraph">Choose syntax that your team can realistically maintain, review, and debug. Configuration drift caused by poorly understood automation is itself a source of human error.</p>



<h3 class="wp-block-heading">Align With Your Target Infrastructure Platform</h3>



<p class="wp-block-paragraph">If you are deploying primarily to a single cloud provider, the native tooling for that platform is worth evaluating first:</p>



<ul class="wp-block-list">
<li><strong>AWS</strong> users should evaluate CodePipeline, CodeDeploy, CodeCommit, and OpsWorks. CodePipeline integrates with GitHub and Jenkins and uses JSON to define pipeline structure. OpsWorks is essentially managed Chef, meaning automation code can be redeployed outside AWS with minimal changes.</li>
<li><strong>Microsoft Azure</strong> users may prefer Azure DevOps (formerly VSTS) and Azure Automation with PowerShell runbooks.</li>
<li><strong>Multi-cloud or hybrid</strong> environments favor cloud-agnostic tools such as Terraform and Ansible, which can target on-premises servers, private clouds, and multiple public clouds from a single codebase.</li>
</ul>



<p class="wp-block-paragraph">The trade-off with native cloud tools is vendor lock-in at the pipeline level. However, because the underlying automation code is often portable—OpsWorks uses standard Chef cookbooks, CodePipeline integrates with third-party tools—the practical lock-in risk may be lower than it first appears.</p>



<h3 class="wp-block-heading">Plan for Cross-Cloud Compatibility From the Start</h3>



<p class="wp-block-paragraph">Organizations committed to hybrid or multi-cloud strategies should prioritize tools that work across environments. Absorbing the short-term cost of learning a cloud-agnostic DSL—such as Terraform&#8217;s HCL or Ansible&#8217;s YAML—pays long-term dividends when workloads need to move between providers or when on-premises infrastructure must be managed alongside cloud resources using a consistent toolchain.</p>



<h2 class="wp-block-heading">Why Automation Matters for Reducing Human Error</h2>



<p class="wp-block-paragraph">Manual deployment processes are inherently error-prone. Steps get skipped, environment-specific configuration values get entered incorrectly, and runbooks drift out of sync with reality. Automated deployment tools address this by encoding deployment logic as versioned, testable, repeatable code. When a deployment fails, the failure is reproducible and debuggable. When it succeeds, the same code can be applied consistently across development, staging, and production environments—eliminating an entire class of &#8220;works on my machine&#8221; defects.</p>



<p class="wp-block-paragraph">The goal is not to replace human judgment but to remove humans from the execution of repetitive, high-stakes steps where fatigue and distraction introduce risk. Engineers remain responsible for designing, reviewing, and approving the automation—making those decisions the focus of human attention rather than the mechanics of running commands on production servers.</p>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">Automated deployment tools fall broadly into four categories: source code management and build automation, continuous integration, application deployment and configuration management, and infrastructure deployment (IaC). The boundaries between categories are porous, and many tools serve multiple roles. Effective tool selection requires a holistic view of the CI/CD pipeline, an honest assessment of team expertise and budget, attention to language and infrastructure compatibility, and a deliberate decision about how much vendor-specific integration is acceptable given your multi-cloud strategy.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/automated-deployment-tools-mitigate-the-risk-of-human-error-in-devops/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Build and Buy: The Right Strategy for Staffing a DevOps Environment</title>
		<link>https://www.bestdevops.com/build-and-buy-key-to-forming-devops-environment/</link>
					<comments>https://www.bestdevops.com/build-and-buy-key-to-forming-devops-environment/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Mon, 09 Jan 2017 06:03:40 +0000</pubDate>
				<category><![CDATA[Build and Release]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Process]]></category>
		<category><![CDATA[IT Training]]></category>
		<category><![CDATA[DevOps Advice]]></category>
		<category><![CDATA[DevOps environment]]></category>
		<category><![CDATA[DevOps Experts]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=268</guid>

					<description><![CDATA[Successfully adopting DevOps isn't purely a hiring problem or a training problem—it's both. Learn why the smartest CIOs combine targeted external hiring with deliberate upskilling of existing staff.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on reporting originally published at <a href="https://searchcio.techtarget.com" rel="noopener">searchcio.techtarget.com</a>. Statistics cited reflect surveys conducted in 2015–2016 and should be treated as historical context rather than current benchmarks.</em></p>



<h2 class="wp-block-heading">DevOps Has Moved Past the Hype Cycle</h2>



<p class="wp-block-paragraph">By the mid-2010s, DevOps had firmly established itself as a mainstream enterprise discipline rather than an emerging trend. Survey data from that period illustrated rapid adoption: the 2016 RightScale State of the Cloud survey reported that 74% of 1,060 IT professionals had adopted DevOps in their organizations, up from 66% in 2015. A separate Vanson Bourne report commissioned by Appvance found that 73% of 200 IT decision-makers had adopted some DevOps processes.</p>



<p class="wp-block-paragraph">The compensation story was equally striking. Puppet&#8217;s 2016 DevOps Salary Report found that 58% of practitioners earned more than $100,000 annually—up from 47% the prior year—while 43% of managers exceeded $150,000, compared with just 26% in 2015.</p>



<p class="wp-block-paragraph">This growth created intense demand for DevOps engineers and raised an important strategic question: how should an organization actually staff a DevOps transformation?</p>



<h2 class="wp-block-heading">The Core Insight: It&#8217;s Not Build vs. Buy—It&#8217;s Build and Buy</h2>



<p class="wp-block-paragraph">A common instinct among CIOs is to treat DevOps adoption as a recruiting problem: find experienced DevOps engineers, hire them, and the transformation follows. IT staffing experts and analysts push back on this framing. You can&#8217;t build a DevOps environment simply by purchasing talent. Equally, you can&#8217;t retitle existing staff as &#8220;DevOps engineers&#8221; and expect the culture and practices to appear on their own.</p>



<p class="wp-block-paragraph">James Stanger, senior director of products at CompTIA, framed it directly: <em>&#8220;People who just want that trained DevOps person are kind of barking up the wrong tree. What they need are people who are in operations or development who have a willingness to learn about each other.&#8221;</em></p>



<p class="wp-block-paragraph">The practical answer is a deliberate combination: hire externally for specific hard-to-build technical skills, then use those new hires to accelerate the upskilling of existing staff who bring irreplaceable organizational knowledge.</p>



<h2 class="wp-block-heading">What DevOps Actually Requires</h2>



<p class="wp-block-paragraph">DevOps is a methodology—roughly a decade old at the time of the original reporting—in which software development and operations teams collaborate closely throughout the entire software lifecycle: building, testing, and releasing software frequently and in small increments. The goals are faster delivery, higher quality, and better security. DevOps depends on both cultural change and specific enabling technologies.</p>



<p class="wp-block-paragraph">An organization adopting DevOps therefore needs two distinct types of capability:</p>



<ul class="wp-block-list">
<li><strong>Collaborative mindset and cross-functional fluency:</strong> Developers who understand operations constraints, and operations engineers who understand the development lifecycle.</li>
<li><strong>Specific technical skills:</strong> Proficiency with the tools and platforms that make continuous delivery and infrastructure automation possible.</li>
</ul>



<h2 class="wp-block-heading">Where to Buy: Technical Skills That Are Hard to Build Quickly</h2>



<p class="wp-block-paragraph">Connor Leech, a senior technical recruiter at tech-staffing agency Mondo, identified the technical areas where external hiring typically makes the most sense. Organizations moving to DevOps commonly need people who can:</p>



<ul class="wp-block-list">
<li>Automate infrastructure provisioning and application deployment pipelines</li>
<li>Design systems that automatically scale in response to demand fluctuations</li>
<li>Work fluently with major cloud providers such as AWS</li>
</ul>



<p class="wp-block-paragraph">The specific tools and technologies that map to these needs include:</p>



<ul class="wp-block-list">
<li><strong>Configuration management and automation:</strong> Puppet, Chef</li>
<li><strong>Application performance monitoring:</strong> New Relic</li>
<li><strong>Scripting and general-purpose programming languages:</strong> Python, Ruby, PHP</li>
<li><strong>Containerization:</strong> Docker (container runtime for packaging and deploying applications consistently across environments)</li>
</ul>



<p class="wp-block-paragraph">The reason external hiring makes sense here is pragmatic. These tools are complex, and hiring managers consistently want candidates who have used them in large production environments—not just experimented with them in sandboxes. Training existing staff to production-level proficiency in multiple platforms simultaneously is slow and risky when a transformation is underway.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;It&#8217;s definitely possible to retrain existing engineers in these areas, but because the tools are kind of complex, [CIOs] want people who have used them rather than have to teach people on them. It&#8217;s a common theme with hiring managers: They want someone who has not only played around with these, but have used them in a large production environment.&#8221;</p><cite>— Connor Leech, Senior Technical Recruiter, Mondo</cite></blockquote>



<h3 class="wp-block-heading">Using Contract Engineers as a Force Multiplier</h3>



<p class="wp-block-paragraph">One effective model is bringing in experienced DevOps engineers on short-term contracts—typically three to six months. These contractors come in, establish automation pipelines, define standards, and actively upskill the existing team. They are expensive, but they function as a force multiplier: when they leave, the permanent team is meaningfully more capable than it was before.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;What&#8217;s really common is bringing in DevOps engineers as contractors. You bring in people on contract for six months, and they come in, help automate and ramp everyone up and then go and do another contract. They&#8217;re generally pretty expensive, but they&#8217;re incredibly valuable. They can turn a company&#8217;s existing engineers into DevOps engineers.&#8221;</p><cite>— Connor Leech, Mondo</cite></blockquote>



<h2 class="wp-block-heading">Where to Build: Mindset and Organizational Knowledge</h2>



<p class="wp-block-paragraph">Technical skills are necessary but not sufficient. DevOps depends on a fundamentally collaborative way of working—the deliberate dismantling of the wall between development and operations. This requires a different kind of capability that is much harder to hire for and much easier to cultivate in existing staff.</p>



<p class="wp-block-paragraph">Stanger identified the key characteristics of good internal DevOps candidates:</p>



<ul class="wp-block-list">
<li>Curiosity about the other side of the dev/ops divide, even if their primary expertise leans one way</li>
<li>Familiarity with project management disciplines to keep iterative delivery cycles on track</li>
<li>Comfort working within agile and Scrum frameworks, which are common structures in DevOps environments</li>
<li>Willingness to share responsibilities that were previously siloed</li>
</ul>



<p class="wp-block-paragraph">Critically, Stanger argued that many existing IT professionals already possess the raw material for this. Developers have often had some exposure to operations concerns, and operations engineers frequently have development experience. The gap is not as wide as it might appear—what&#8217;s often missing is not knowledge but permission and encouragement to apply it.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;Many of the people who have been working in programming for years, if they have the right mentality, are already DevOps people. Anyone could easily be turned into that DevOps person. Most people have the seeds of DevOps in them, but the seeds haven&#8217;t been nurtured.&#8221;</p><cite>— James Stanger, CompTIA</cite></blockquote>



<h2 class="wp-block-heading">Why Existing Staff Are Not Optional</h2>



<p class="wp-block-paragraph">Jay Lyman, a principal analyst covering DevOps at 451 Research, reinforced this dual approach from an analyst&#8217;s perspective. Organizations need an infusion of new skills from external hires, but they also depend on the organizational context and institutional knowledge that existing staff carry. No external hire will understand the business&#8217;s specific systems, constraints, and history as well as a long-tenured internal engineer.</p>



<p class="wp-block-paragraph">There is also a practical alignment benefit. IT professionals who understand that DevOps skills increase their market value are generally motivated to participate in training and upskilling programs. This makes change management easier—staff become advocates for the transformation rather than passive recipients of it.</p>



<h2 class="wp-block-heading">The Leadership Imperative: Understand and Sell DevOps</h2>



<p class="wp-block-paragraph">Staffing strategy is only one part of the equation. CIOs and engineering leaders must themselves develop a genuine understanding of DevOps—not just at the conceptual level, but operationally. They need to be able to articulate what DevOps delivers for the business (speed, quality, reduced risk) and why it requires changes to how teams are structured and how work is measured.</p>



<p class="wp-block-paragraph">Not all staff will embrace the transition. Some IT professionals are more comfortable in traditional, more sequential delivery models. This is not necessarily a problem—some projects and contexts do suit more structured, phased approaches. But organizations moving fully toward continuous delivery may eventually face a mismatch between those delivery expectations and staff who resist the required way of working. In those cases, external hiring may eventually be necessary not just to add skills but to replace resistance.</p>



<h2 class="wp-block-heading">Summary: A Practical Staffing Framework</h2>



<figure class="wp-block-table"><table><thead><tr><th>Dimension</th><th>Buy (External Hire)</th><th>Build (Internal Development)</th></tr></thead><tbody><tr><td>Technical tooling</td><td>Configuration management (Puppet, Chef), containers (Docker), cloud platforms, monitoring</td><td>Gradually, with coaching from experienced hires</td></tr><tr><td>Scripting/programming</td><td>When production-level proficiency is needed immediately</td><td>For staff who have foundational skills and willingness to deepen them</td></tr><tr><td>Cross-functional fluency</td><td>Less effective—culture cannot be hired in</td><td>Primary approach; identify staff already curious about both sides</td></tr><tr><td>Organizational knowledge</td><td>Cannot be bought; takes years to develop</td><td>Primary advantage of existing staff</td></tr><tr><td>Agile/Scrum practices</td><td>May need external coaching initially</td><td>Can be taught relatively quickly to motivated staff</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The organizations that successfully form a DevOps environment are those that resist the false choice between hiring and training. They hire deliberately and specifically for the hardest-to-build technical skills, use those new hires to accelerate team capability, and invest simultaneously in developing the collaborative mindset and cross-functional fluency that no job posting can deliver.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/build-and-buy-key-to-forming-devops-environment/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
