DevOps, as a buzzword, has grown a lot in popularity over the years. What does it mean when you’re told, by one person or another, that you need to “do” DevOps?
Liquid error: internal
What I will attempt to do is look at the process of DevOps holistically and iron out some basic definitions that will, at the very least, get you started on your DevOps journey.
DevOps is a journey, not a destination. You don’t magically arrive at some point and all-of-a-sudden reach DevOps nirvana. It is a continuous cycle of improvement, fast-failures, and the moment you realize you are deploying and integrating as fast as you can, the bar is raised higher. Your customer is already 2 steps ahead of you and needed your changes yesterday.
One would be foolish to think that DevOps doesn’t start with code. We all write code and deploy it in some manner. So how we write our code is just as important as how we deploy our code.
I follow Jocko Willink ’s podcast and one of his core philosophies is Discipline Equals Freedom. This is very true for Software Engineering. The more disciplined you are in writing and managing your code, the more freedom you have to write new features, get restful sleep, etc.
For many years, Git has been the leader in source code management. While there are other tools out there that do the trick, this article will focus on Git. You can have perfectly written code, but if your team is not disciplined in managing those changes, you’re asking for the opposite of freedom.
Remember, DevOps is a journey, so if you at least start somewhere, you can gradually get to the point where you want to be and keep tweaking as time goes on.
Commit early and often.
Make each commit message meaningful.
Make your commit changes small and transactional.
Don’t be a commit hoarder. Push your code to a remote (even if you’re the only dev)
Never rewrite shared history. Just don’t. Stop even thinking about it.
Let me explain.
If you’ve been hacking away for hours and all-of-a-sudden it’s 6pm, you’re tired and want to go home, but you haven’t made any commits. So? What do you do?
You lazily add ALL of your changes into ONE commit, and give it a crappy message because it’s 6pm and you’re out of creative juices. So, you end up with the following:
trying to figure out the problem with this sidebar
…which contains changes to 53 files with 3,564 additions and 4,352 deletions. In a hurry, you slapped your laptop closed and stuffed it in a bag, desperately trying to beat rush-hour. When you arrive home, you’re frantically struggling to find your laptop only to realize you left it on the roof of your car and it’s now scattered into pieces on the Interstate.
It’s ok, IT has another laptop they will loan you…except for the fact that you didn’t push your changes to the remote repo (in this case, GitHub). Now, you’re chained to your desk for the afternoon trying to figure out everything you worked on the day before after spending the first half of the day getting your development environment back up.
Commit your code minimally with meaningful messages and push them. Your future self (and all those that come after you) will thank you. Or they won’t…but, at least you can say you did your part.
Git is so flexible that you can create an unlimited number of branches, tags, commits, and use as many remote repos as you want. So, having a good strategy and working agreement with your team is important to avoid messes like the one above.
Things to remember:
- master should be kept clean
- branches should be short-lived and have a meaningful name
- branch names should be standardized (but, not over-engineered)
There are several established workflows available. For newer and less-disciplined teams, you can start with a Centralized Workflow; however, since no one likes merge conflicts, it’s better to keep code isolated and integrate it in more measured approaches. I like the Feature-Based Workflow since it aligns with Trunk-based Development . Mainly because I like keeping code fresh in everyone’s own repo, yet keeping features isolated just enough so you have a stable platform to operate off of.
The cool thing about FBW & TBD is if you have nifty deployment pipeline and Continuous Integration tools like Jenkins or Travis CI, this workflow fits oh-so-nicely with those tools.
Let’s talk about Pull Requests. For one, back when Git was born, there was no GitHub. Linus Torvalds would get emails (yes, emails) to pull other contributors’ code into the master Linux kernel’s repository. Now, we’ve all grown accustomed to Pull Requests (spoiled!), but as a result, if poorly managed, PRs can be as dangerous as an untested merge.
Pull Requests have become a glorified rubber stamp.
Git, for me, has been a valuable tool in making me a better Software Engineer. Git gives you the ability to build a wall, brick-by-brick, and should that wall topple over, allow you to stand it back up as if it never fell. As such, if Git can help a developer build on what works and use disposable experimentation to get better, why shouldn’t we use Pull Requests to get better?
Disposable Experimentation. Create a branch to experiment in, realize it’s not going to work, and just delete it — abandoning the work — with nobody else ever seeing it (even if you’ve pushed other branches in the meantime). Source: Git About
Pull Requests should be a discussion. It should be where developers in a team come together and bang and hammer the code to a point of acceptance by the team , not just the ones reviewing the PR.
Am I saying that each PR has to be this lengthy code-review process? No.
A single PR Review should take minutes, no more than there are fingers on one hand. If you find PR review is taking more time to review and pulling you and your team away from writing code, you need smaller Pull Requests.
A PR should be a opportunity for the team to review the code and keep other developers in check by suggesting better approaches, asking questions about functionality, and ensuring quality.
Their are two actors in play. The Pull Request submitter and the team.
It is the responsibility of the submitter to ensure the feature (assuming they are submitting a feature branch to pull into master) is complete. By “complete”, we mean that feature meets the criteria for that team’s definition of done.
Most PRs (Github and Bitbucket) contain a subject and a description field. The subject should be a one-sentence summary of the change and the description should describe the change being submitted.
I like to take it a step further by using GitHub Templates for Pull Requests and use pre-defined templates for each PR. It takes the thought out of “what should I write in this giant field”.
Here are some things I like to ask PR submitters:
- A brief blurb about the change
- Screenshots to show the code is working/has been tested
- Why is this change needed/necessary?
- Links to related GitHub or JIRA issues
At the bottom of the template, I like to know if the PR is a new feature, bug fix, or other (describe).
Below that, I like to include check boxes submitters can check off to ensure they’ve done their due diligence to ensure completion.
✓ Does this change require a change to documentation?
✓ Has the documentation been updated or new documentation added?
✓ Has their been tests written for this change?
✓ Do all new and existing tests pass?
Beyond that, you can add to those check boxes if your change requires stuff like emulation, package updates, etc.
The point is… as a Submitter, it is your responsibility to communicate to the team your change and that you have certified that change is ready to merge into the main code.
Ideally, you have more than one set of eyes on the code (not including the Submitter). Yes, that’s the submitter and 2 or more reviewers. For the sake of not over-engineering, you should have a limited number of people that can make a GO/NO GO decision for the PR if it’s not ready. Feedback is useful. Too much feedback and you start to get diminishing returns.
The most powerful action for a PR is to reject it altogether. Remember that.
If you have good PR discipline, congratulations! Your job should be easy. If the Submitter has already done their due diligence and properly tested the change and you have no merge conflicts, the remainder of your duties are nit-picking code formatting and variable names.
Speaking of code-formatting, you should have everyone aligned with the same linting and pre-commit formatting rules with a tool like Prettier.
Anything that can take the thought out of PR review and make it easier for both the Submitter and the Reviewers to integrate code make for happy code.
100% code coverage is easy, if you know how to cheat the system. It’s easy to write tests that can cover all of your code, but it’s much more challenging to write test cases that cover all of your scenarios. I’m reminded of Testivus in this instance.
How much code coverage is enough? 80 percent and no less! 😉
When you have tests that cover your scenarios, that will organically increase your code coverage, which in-turn, increases your code confidence.
If you have 60% code coverage and 100% scenario coverage, you’re definitely on the right path. Keep plugging at it, there are probably more scenarios you haven’t thought of.
Start with the basics. “Does this method/function/page exist?” That’s a test! Build on that to include “This button should be blue” all the way down to using Gherkin language.
**Feature:** Some terse yet descriptive text of what is desired
In order to realize a named business value
As an explicit system actor
I want to gain some beneficial outcome which furthers the goal
**Scenario:** Some determinable business situation
**Given** some precondition
**And** some other precondition
**When** some action by the actor
**And** some other action
**And** yet another action
**Then** some testable outcome is achieved
**And** something else we can check happens too
Given I am on this page
When I click the checkout button
Then I should be taken to the order summary screen.
The neat thing about Gherkin is that you can write user stories in the same language and use testing tools like Cucumber to test acceptance criteria in addition to units of code.