tag:dougborg.org,2014:/feedDoug Borg2015-01-07T21:13:54-08:00Doug Borghttp://dougborg.orgdougborg@dougborg.orgSvbtle.comtag:dougborg.org,2014:Post/what-makes-a-good-build-dot-gradle2015-01-07T21:13:54-08:002015-01-07T21:13:54-08:00What makes a good build.gradle?<p>A <code class="prettyprint">build.gradle</code> usually starts out innocently enough as a simple, easy to understand file. After all, that’s why you (or someone on your team) chose Gradle as your build system! However, if you don’t spend time refactoring it and give it the love and attention it needs and deserves, it can go awry fairly quickly and come back to haunt you at 1am when you should really be <del>out drinking</del> sleeping, not fiddling with your project’s broken Gradle build. You can end up with a file hundreds of lines long nobody on your team wants to touch or even look at. In this post, I will explain what I think makes a good <code class="prettyprint">build.gradle</code> and outline a few strategies or things to consider in order to keep it that way.</p>
<p>My perspective on builds is shaped by many years spent working on build and deployment automation systems in a corporate environment where you will generally find many similar types of projects. Sharing build logic and conventions becomes particularly critical to maintain sanity while working in this type of environment. Some of these things may not necessarily apply to a hobby OSS project, or if you are using other build systems, but many will.</p>
<h1 id="another-buildgradle-gone-bad_1">Another build.gradle gone bad… <a class="head_anchor" href="#another-buildgradle-gone-bad_1">#</a>
</h1>
<p>My colleague <a href="http://sethgoings.com">Seth Goings</a> (<a href="http://twitter.com/SethGoings">@SethGoings</a>) and I were having a <del>bitch session</del> conversation recently after I stumbled on a particularly complex <code class="prettyprint">build.gradle</code> file. Seth realized part of the problem was we haven’t really set good expectations for what a good <code class="prettyprint">build.gradle</code> file should look like:</p>
<blockquote>
<p>I’ve been thinking about how we don’t really have a good “goal” for Gradle<br>
builds (internally in this team or expressed). [W]hat do we really care<br>
about? We care it’s clean… sure… but that’s so subjective, or has<br>
been.</p>
</blockquote>
<p>– Seth Goings</p>
<p>As I have said before, it is impossible to hold people accountable to expectations you never set.</p>
<p></p><blockquote class="twitter-tweet" lang="en">
<p>You can’t hold people<br>
accountable to expectations you never set.</p>— Douglas Borg (@doug_borg)<br>
<a href="https://twitter.com/doug_borg/status/459142818649608192">April 24,<br>
2014</a>
</blockquote>
charset="utf-8">
<p>I realized I should take my own advice and start setting some expectations for a good Gradle build. I brainstormed a few things I think are important and had some further discussions with Seth and my other CI / DevTools colleague at <a href="http://www.readytalk.com">ReadyTalk</a> (<a href="http://twitter.com/ReadyTalkGeeks">@ReadyTalkGeeks</a>), Jason Miller (<a href="http://twitter.com/stormbeta">@stormbeta</a>).</p>
<h1 id="a-good-code-classprettyprintbuildgradlecode-s_1">A good <code class="prettyprint">build.gradle</code> should: <a class="head_anchor" href="#a-good-code-classprettyprintbuildgradlecode-s_1">#</a>
</h1><h2 id="be-brief_2">Be Brief. <a class="head_anchor" href="#be-brief_2">#</a>
</h2>
<p>As a rule, I feel less than 100 lines is ideal with a general preference for smaller files. If your build script is getting longer than 100 lines, it is a “code smell” and you should consider <a href="http://www.gradle.org/docs/current/userguide/organizing_build_logic.html">extracting parts of your build</a> into the <code class="prettyprint">buildSrc</code> folder, <a href="http://plugins.gradle.org/">find a plugin</a>, or <a href="http://www.gradle.org/docs/current/userguide/custom_plugins.html">create a plugin</a> to hold any custom build logic.</p>
<p>In our lunch conversation, Seth mentioned one of the biggest things that attracted him to Gradle in the first place was the classic “Hello, world!” Gradle example.</p>
<p>A simple Java project built with Gradle looks something like this:</p>
<pre><code class="prettyprint lang-Groovy">apply plugin: java
</code></pre>
<p>With a simple one-liner you get an amazing amount of build functionality based around conventions. If you are new to Gradle or would just like a refresher on just what, exactly, the <code class="prettyprint">java</code> plugin does, check out Petri Kainulainen’s excellent <a href="http://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-our-first-Java-project/">Getting Started with Gradle post</a> or Gradle’s own <a href="http://www.gradle.org/docs/current/userguide/tutorial_Java_projects.html">Java QuickStart guide</a>.</p>
<p>This is truly the power of Gradle: the ease with which you can define your own conventions and build functionality and wrap it up into a plugin or set of plugins. You can then apply those plugins to all your organization’s projects.</p>
<h2 id="be-declarative_2">Be Declarative. <a class="head_anchor" href="#be-declarative_2">#</a>
</h2>
<p>More than brief, your <code class="prettyprint">build.gradle</code> should be <a href="http://latentflip.com/imperative-vs-declarative/">declarative</a>. It should describe your project: what sort of project it is, what dependencies it has, the artifacts it creates, and where they go. You may even want to place some of that information in organization-specific plugins as we do @ ReadyTalk.</p>
<p>Imperative flow control statements (<code class="prettyprint">if</code>, <code class="prettyprint">case</code>, etc.), task declarations, import statements and the like should be avoided as much as possible. While it is entirely possible to create plugin classes and place any other sort of other Groovy and Java code within your <code class="prettyprint">build.gradle</code> file, I do not believe it is a good practice. By all means use the flexibility of Groovy to experiment or troubleshoot problems with your build, but avoid it as much as possible in your “production” <code class="prettyprint">build.gradle</code> in master. These sorts of things are also smells, and you should consider using or creating a plugin of some kind.</p>
<p>You should always strive to get your build to a point where you just have a <code class="prettyprint">plugins</code> block, a <code class="prettyprint">dependencies</code> block, an <code class="prettyprint">artifacts</code> block, and a plugin extension configuration block here or there. That’s it. Really. With very few exceptions, build functionality should be provided by plugins you configure declaratively.</p>
<p>Gradle is doubling down on a declarative, model-based approach in future development, so get used to thinking about your build this way if you want to keep up with the cool kids. Check out <a href="http://www.gradleware.com/video/gradle-into-the-future/">Adam Murdoch’s talk</a> from Gradle Summit 2014 if you are interested in hearing more on that and other things in store for Gradle.</p>
<h2 id="bootstrap-itself_2">Bootstrap Itself. <a class="head_anchor" href="#bootstrap-itself_2">#</a>
</h2>
<p>First of all, if you are not using the <a href="http://www.gradle.org/docs/current/userguide/gradle_wrapper.html">Gradle Wrapper</a>, you should set that up for your project right away. I’ll wait here while you go do that.</p>
<pre><code class="prettyprint lang-bash">$ gradle wrapper # <-- Run this on your Gradle project right now!
</code></pre>
<p><img src="http://v1.memecaptain.com/9e57b8.jpg" alt="If you don't use the Gradle Wrapper, you're gonna have a bad time!"></p>
<p>Gradle is an ever-evolving tool and as much as the Gradle team strives to maintain backwards compatibility, sometimes things break - especially if you are using incubating features. Using the Gradle Wrapper is crucial for reproducible builds, and is just plain convenient: you don’t need Gradle installed in order to run a Gradle build.</p>
<p>Similarly, pre-buildtime dependencies on anything other than Java should be minimized as much as possible. The Gradle Wrapper gets rid of a pre-buildtime dependency on Gradle itself, but if your build uses other SDKs, custom compilers, utilities etc., they should be managed in much the same way. Set them as <code class="prettyprint">dependencies</code> in your <code class="prettyprint">build.gradle</code> (or as part of a plugin) and extract or set them up at buildtime as part of running the Gradle build.</p>
<p>A goal I have for any project I get involved with is for a new developer to be able to check out the project from source control, run <code class="prettyprint">./gradlew</code> and have everything “just work.” This also helps tremendously with managing your CI servers. If every project’s build takes care of itself, it makes maintaining CI servers much easier and you don’t have to worry about version conflicts, etc. between projects running on the same build server. As a side effect, you also grant more freedom and flexibility to your dev teams to take care of their own projects’ dependencies without having to go through a central Configuration Management gatekeeper (an all-too-common anti-pattern in my opinion).</p>
<h2 id="have-a-single-entry-point_2">Have A Single Entry Point. <a class="head_anchor" href="#have-a-single-entry-point_2">#</a>
</h2>
<p>I like setting up the task you want a developer to run when they first come into the project as the <a href="http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html#sec:default_tasks">default task</a>. Again, any developer (or other interested party) should be able to checkout your project, run <code class="prettyprint">./gradlew</code> and have everything “just work” including things like compiling the code, running tests, static analysis tools, and assembling artifacts for as many platforms / variants as possible.</p>
<p>I also like having a single <code class="prettyprint">ci</code> task for your CI server to run. The <code class="prettyprint">ci</code> task should have the main “developer” task as a dependency and just add on whatever publishing and reporting tasks your CI server needs to perform. I prefer to keep any sort of CI server tasks defined in the Gradle build. I want the project configuration in my CI server to be dead simple: run <code class="prettyprint">./gradlew ci</code>.</p>
<p>Right now I bet you are saying to yourself, “Self, didn’t Doug just say I should have a <em>SINGLE</em> entry point? It seems like he is talking about <em>TWO</em> entry points now…”</p>
<p>Ah, you make an excellent point, but I have the solution to your imagined quandary! If you make your <code class="prettyprint">ci</code> task smart enough, it can do the right thing based on the context it is running in (user, branch, platform, etc.) and you can collapse the “developer” task into the <code class="prettyprint">ci</code> task and truly have a single entrypoint for everyone. We are actually working on a just such a “smart” <code class="prettyprint">ci</code> task as part of our open-source <a href="https://github.com/ReadyTalk/gradle-readytalk-ci">readytalk-ci</a> plugin.</p>
<h2 id="mind-its-own-business_2">Mind Its Own Business. <a class="head_anchor" href="#mind-its-own-business_2">#</a>
</h2>
<p>We haven’t seen this too much since migrating from Ant to Gradle a couple years ago, but I feel like it is something worth mentioning as it is still possible to fall into this trap with Gradle (or Ant, or any other build system, really).</p>
<p>Among the many other problems with our old Ant builds, one of the major causes of build instability came from the fact many or our projects reached directly into other projects to grab files, or do other work instead of just depending on the outputs or artifacts of those projects. A build (for <em>ANY</em> project using <em>ANY</em> build system), should mind its own business. It should only depend on specific outputs or artifacts of other projects and not be dependent on the way another project is structured or how it goes about producing those outputs.</p>
<p>If you are a software developer worth your mechanical keyboard, this really should not be a new idea to you. A build “minding its own business” is just another way to describe encapsulation and separation of concerns. Good software engineering principles apply to all code - the code you write for your product as well as the code you use to build and deploy it.</p>
<p>Along the same lines and of more specific importance to Gradle, is the idea project builds should also be <a href="https://gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects">decoupled</a>. This can sometimes be tricky since there are some initially attractive-sounding features Gradle provides which end up coupling your projects together. It is possible for one project to access another project’s object model and modify it - <em>DO NOT DO THIS</em>. Take the time to read through all the documentation on <a href="https://gradle.org/docs/current/userguide/multi_project_builds.html">multi-project builds</a> to gain a better understanding of the ways projects can come to be coupled and ways to mitigate or avoid it altogether.</p>
<h2 id="be-platform-independent_2">Be Platform Independent. <a class="head_anchor" href="#be-platform-independent_2">#</a>
</h2>
<p>As much as possible, a <code class="prettyprint">build.gradle</code> should be able to run on Windows, Linux, OSX, etc. Gradle strives to be platform independent and your build should strive for the same. Again, many “impossible-to-solve” multi-platform build issues can be actually be addressed by leveraging other tools. You can leverage tools like Docker, Fig and Vagrant as part of your Gradle build to solve even the hardest dependency and cross-platform build problems.</p>
<p>One of the biggest features I am waiting on to be implemented in the Gradle Daemon is something that would allow me to easily define a multi-platform build that runs in parallel, distributed across executors running on a number of different machines. We get around this now on our CI builds using Jenkins Matrix builds, but it is a mess and the solution we have worked up for developer builds is a kludgy hack using ssh and bash scripts around the actual Gradle Build.</p>
<h1 id="wrapping-it-up_1">Wrapping it up…. <a class="head_anchor" href="#wrapping-it-up_1">#</a>
</h1>
<p>Wow. This post ended up being a bit longer than I intended, so thanks for sticking it out! I still feel like I am missing some things, but this will have to do for now.</p>
<p>To bring it all back together, I think a good <code class="prettyprint">build.gradle</code> is a short, declarative, and descriptive file that keeps to itself and has a dead-simple way to invoke it. The Gradle build it describes should minimize the amount of setup and documentation necessary to interact with your project. It should stick to conventions defined elsewhere and shared with other similar projects.</p>
<p>When you are working on a <code class="prettyprint">build.gradle</code> file, you should always feel a little dirty when you open up configuration or task closure. Every time you do, you are going rogue and defining an exception to a convention or model defined, or should be defined, in a plugin. Consider generalizing your exception so it is useful to other projects by contributing to an existing plugin or creating a new one if you think you are truly a special and unique snowflake.</p>
<p>There are clearly reasons some of the principles I outlined above will not work in all cases, but they are things to keep in mind and work towards. Not all of our projects actually stick to these points, but they <em>SHOULD</em>.</p>
<p>Every <code class="prettyprint">build.gradle</code> is a work in progress and you will always have to balance the time you spend on improving your build with working on your actual product. That said, software builds are often neglected and accumulate hidden costs (AKA technical debt) which can be hard to see or calculate. Consider spending some time improving your builds - even small improvements that get you closer to the ideals I outlined above can pay back huge dividends in the long run.</p>
<p>So, what do you think? Did I miss something? Do you want to have a nerd-fight over what I said about your beloved, 1,394-line <code class="prettyprint">build.gradle</code> you think is perfectly fine? Don’t like the cut of my jib? Hit me up on Twitter or e-mail and let me know!</p>
<p>I posted this to reddit as well: <a href="http://redd.it/2rreoh">comment here</a> and let’s get a good discussion going!</p>
tag:dougborg.org,2014:Post/comcast2014-12-03T15:13:05-08:002014-12-03T15:13:05-08:00Comcast<p>Chris: Hi, thanks for shopping Comcast my name is Chris. Do you have any questions about our products or services that I can help answer?</p>
<p>You: I am moving to a new house. What is the best way to set that up and ensure I get the best deal?</p>
<p>Chris: I’d be more than happy to assist you in getting new services.</p>
<p>Chris: Do you mind if I ask a few questions to make sure we get the ideal package that best suits your needs?</p>
<p>You: Sure</p>
<p>Chris: Thank you! Just to check before we move on, are you a current <br>
Comcast customer or have you had Comcast service in your name within the last 120 days?</p>
<p>You: Yes.</p>
<p>Chris: Thank you for being a Comcast customer!</p>
<p>Chris: May I have your complete address and zip code, as prices and plans <br>
vary by address?</p>
<p>You: For the new house or current house?</p>
<p>Chris: For the new house please.</p>
<p>You: XXXXXXXXXX Denver CO XXXXXX</p>
<p>Chris: Thank you for providing your complete address with zip code.</p>
<p>Chris: One moment please as I will check your address for the availability of our service in your area.</p>
<p>Chris: Thank you for waiting.</p>
<p>Chris: May I know what product are you interested in?</p>
<p>You: I really just want fast internet @ 40-50mbps</p>
<p>You: i do not care about tv or phone packages so please do not try to sell me them</p>
<p>Chris: That’s a great choice!</p>
<p>Chris: To make sure it suits your needs, may I ask what types of things do you do online?</p>
<p>You: I have a quote from centurylink for $35/month for 40mbps</p>
<p>You: for 1 year</p>
<p>You: if you can’t do better than that, then I will go with them.</p>
<p>You: that’s w/ an upgrade to get 20mbps upload</p>
<p>Chris: I understand, just to set the proper expectation since you are already a Comcast customer and you are adding the new service in a different address regular rates will apply to you.</p>
<p>You: ok then you are saying I should go with centurylink?</p>
<p>Chris: I just only want to let you know.</p>
<p>Chris: May I ask what types of things do you do online?</p>
<p>You: OK so what is the best deal you can get me on internet only @ 40mbps?</p>
<p>You: I know what my bandwidth requirements are, I don’t need you to walk me through a script</p>
<p>Chris: I understand. How many computers or gaming devices do you connect to the internet? Are any of them laptops?</p>
<p>You: I have a few computers and gaming devices and some of them are laptops. I know what I need. Please just tell me the best deal you can give me on a 40-50mbps internet connection. I think you call this Blast Plus?</p>
<p>Chris: Great! May I ask if you have TV or Phone service with other provider?</p>
<p>You: I have a cell phone and I get TV via streaming and HD digital OTA dvr. I told you what I want. Please just give me a quote.</p>
<p>Chris: Before we move on, we currently have amazing offers available to you. I understand that you are interested in getting our Internet service; however, you may want to consider our Double Play offers which include amazing features and would provide you with substantial savings. Would you like to know more about our Double Play packages?</p>
<p>You: I am about to click Buy over at the CenturyLink website….</p>
<p>Chris: I understand, I just wanted to make sure you get the best service as possible.</p>
<p>Chris: Based on the information that you have provided earlier, I would highly recommend the Performance with Blast Internet. This plan has download speeds up to 50 Mbps and upload speeds up to 10 Mbps. This is perfect for gaming in real-time, download/upload files, watch online videos, web surfing, email, social networking online and connect all the devices in your home simultaneously. This is the ideal speed that will cater to your online activities.</p>
<p>You: … And i told you exactly what i want and you are trying to upsell me on other services when i explicitly told you I was not interested in them.</p>
<p>Chris: Performance w/ Blast is around $76.95/mo.</p>
<p>You: Ok thanks.</p>
<p>Chris: How does that sound?</p>
<p>You: Terrible.</p>
<p>You: I can get 100mbps DSL from centurylink for that price.</p>
<p>You: Thanks anyway.</p>
<p>Chris: Did you have any additional questions that I may address?</p>
<p>You: Nope.</p>
tag:dougborg.org,2014:Post/gdub2014-08-27T16:27:23-07:002014-08-27T16:27:23-07:00gdub<p>I wrote a little bash script a while back to help with some inconveniences I ran into while working with <a href="http://gradle.org">Gradle</a> projects. I also used it as an excuse to experiment and play with running an open source project. If you use Gradle, I hope you will find it useful. </p>
<p>Check it out <a href="http://gdub.rocks">here</a>. </p>
<p>Let me know if you think anything about it could be <a href="https://github.com/dougborg/gdub/issues">better</a>.</p>
tag:dougborg.org,2014:Post/hello2014-08-05T18:43:01-07:002014-08-05T18:43:01-07:00Hi.<p>Welcome to the new and improved <a href="http://dougborg.org">dougborg.org</a>! I plan to post about the stuff I work on as a Software Engineer at <a href="http://readytalk.com">ReadyTalk</a> and other related projects and technologies. I focus on software build, test, and deployment automation. Some call this sort of stuff “DevOps” and I don’t usually have the heart to disagree with them. However, I do fall more in the camp of DevOps as a collection of <a href="http://continuousdelivery.com/">practices</a>, <a href="http://agilemanifesto.org/">ideas</a>, and <a href="http://docker.com">tools</a> rather than a <a href="http://blog.petecheslock.com/2013/05/03/devops-in-your-job-title-is-doing-you-harm/">job title</a> or <a href="http://continuousdelivery.com/2012/10/theres-no-such-thing-as-a-devops-team">team</a>. </p>
<p>In any case, I work on the “CI” team at <a href="http://www.readytalk.com/about/careers-readytalk/apply-readytalk">ReadyTalk</a> and we do the DevOps-y things; expect to hear more about it.</p>
<p>I have tried to get started on blogging a few times in the past, so bear with me. I will do my best to keep posts amusing and informative. In the meantime, this:</p>
<p><img src="http://i.imgur.com/G8wuV.jpg" alt="business cat"></p>