As a software engineer who entered the tech industry through a bootcamp, I’ve had the opportunity to teach part-time at the same bootcamp where I learned the ropes. While guiding students through their final projects, I’ve noticed that many teams struggle not because of their coding skills, but because of inefficient workflows. That is why I recommend incorporating some DevOps and Agile practices into your project. By doing so, you can streamline your development process and work more collaboratively with your team
What this Covers
- Common difficulties with building bootcamp projects
- Improve your project planning and progress tracking
- Automate Deployments to Heroku
- Protect your main branch
- Rails testing!
- Tests and Github Actions
The Stack
Common Difficulties with Bootcamp Projects
Bootcamp project teams typically face a number of challenges that can make completing the project more difficult. Some of the most common challenges include:
Communication: One of the biggest challenges for any team is communication. When working on a project, it’s important for team members to communicate effectively and regularly in order to ensure everyone is on the same page and the project is progressing smoothly.
Time management: Bootcamps are typically intensive programs with strict deadlines, so time management is crucial. Team members must be able to manage their time effectively in order to meet project deadlines.
Technical difficulties: Depending on the project, team members may encounter technical difficulties that can slow down progress. This can be particularly challenging for those who are new to coding and may not have the experience to troubleshoot effectively.
Conflict resolution: With any team, conflicts can arise. It’s important for team members to be able to resolve conflicts in a constructive manner in order to maintain productivity and avoid negative feelings.
Motivation: A bootcamp can be intense and require a lot of hard work, which can be challenging for team members who are struggling with motivation. Team leaders in bootcamps must find ways to keep team members engaged and motivated throughout the project.
Quality control: Finally, ensuring that the project meets quality standards can be a challenge. Team members must be diligent in checking their work and testing the project thoroughly in order to ensure it meets the necessary requirements.
Those of you who are reading this who have already done a bootcamp, or even just building a personal project with a team of other learners, you will probably have experienced some of these challenges. The tools and techniques described below are not a cure-all but will certainly help if executed and used correctly. Great workflows create more time for the important conversations and allow you to stay focused on driving the progress of your project.
Improve your project planning and progress rituals in bootcamps
Definition of Done
By far the most important piece of advice in this blog from bootcamp experience is having a clear definition of done for each piece of work, it should look something like this:
“New feature added and working in production environment”
The most important part of this (in the context of this blog) is “working in production environment”. In my experience of amateur projects, work is considered ‘done’ when a PR has been merged, after which a learner will move on to the next piece of work. This often means that work is never deployed and tested, despite being merged. When the deployment eventually happens there are then multiple PRs worth of code which makes debugging more difficult when problems occur.
Simply agreeing with your team that every ticket must be tested and working in production before being considered ‘done’ will go a long way towards a better work-flow, smaller, more regular deployments and easier debugging.
A Better Kanban

The basic Kanban that you may be familiar with (as above) is a great way to track work that’s being done in a project, but just this basic version doesn’t quite capture the workflow in fine enough detail.
To improve the board to better reflect our work flow we will add three columns.
Backlog: A backlog column in Kanban is a prioritised list of tasks waiting to be worked on. It sits at the beginning of the board and represents work that hasn’t started. Unlike “To Do” you are not committed to delivering the work in backlog but it is the place to prioritise and decide one what work you are going to commit to with the time you have.
Under PR: The “Under PR” column in Kanban represents tasks awaiting review before merging into the main codebase.
QA in prod: A “QA in prod” column in Kanban represents tasks being tested in the production environment. It sits towards the end of the board and indicates that the item has been deployed and is being checked for any potential issues before being moved to the “Done” column. Its purpose is to ensure items are thoroughly tested before release to users.

Example Board: https://trello.com/b/QUprS2eo/improved-kanban
Tracking the flow of work with more detail gives the whole team better transparency on the project, encourages everyone to meet that definition of done.
Here is a great article by Kanbanize to learn more about Kanban.
Automated Deployments With Heroku
Now that as a team you’ve agreed on a workflow, what can you do to enable the team to follow that workflow even when under pressure? Firstly we have to understand that even though there are benefits, if a process is difficult to follow it’s unlikely the team will reliably follow that process. We can start with automating deployments.
Why you should automate your deployments in bootcamps
Speed and efficiency, consistency, simplicity and flexibility. With Heroku’s automated deployment process, developers can quickly and easily deploy their application without worrying about the technicalities of the deployment process. Additionally, the deployment process is consistent, reducing the risk of errors. Heroku’s automated deployment process saves time and improves the efficiency of the development process, making it an ideal option for developers of all skill levels.
How to automate your deployments
- Connect your code repository to your Heroku application by navigating to your app dashboard on the Heroku website and selecting the “Deploy” tab.
- Choose the deployment method that best suits your needs. Heroku offers several options, including GitHub integration, Dropbox integration, and Heroku Git.
- Configure your deployment settings, such as the branch to deploy and any necessary environment variables.
- Enable automatic deploys if desired. This feature will automatically deploy your app every time you push changes to your connected repository.
- Set up automatic scaling for your application, if needed, using Heroku’s built-in features or add-ons.
One of the key benefits of automating your deployments with Heroku is that it can help you gain valuable experience in problem-solving with your production environment. By deploying on every pull request, you and your team can identify and fix issues early on, rather than waiting until the last minute to deploy a large batch of changes. This approach allows you to test and refine your deployment process continuously, giving you more opportunities to learn from your mistakes and improve your workflow.
Protect your main branch
Now that you are automating deployment on each merge to main, protect the main branch from being directly pushed to without going though the pull request process. This will mean every piece of code will be seen by at least one other team member, improving the team’s knowledge of the codebase and enforcing the PR process.
What is branch protection?
Branch protection is a feature in Git-based version control systems, such as GitHub, that allows repository administrators to enforce certain rules and safeguards for specific branches. The purpose of branch protection is to prevent unauthorised changes, reduce errors, and ensure code quality by enforcing best practices for collaborative development.
Branch protection can include a variety of rules and safeguards, such as:
- Requiring pull request reviews before merging changes into the branch
- Requiring status checks to pass (such as automated tests) before merging changes
- Restricting who can push changes to the branch (such as only allowing certain users or teams)
- Restricting who can merge changes to the branch (such as only allowing administrators)
- Restricting who can delete the branch (such as only allowing administrators)
- Requiring signed commits or specific commit message formats
- Enforcing certain code quality standards (such as preventing commits that fail code linting checks)
Protecting the main branch in GitHub improves workflow by enforcing rules and safeguards. It ensures code quality by requiring pull request reviews and status checks, reducing errors and saving time. It promotes team collaboration by encouraging feedback and discussion during the review process, enhancing code quality and building a more cohesive team. It also promotes transparency and accountability, helping the team to see changes being made and identify issues. Overall, protecting the main branch leads to a stable, reliable, high-quality codebase and a streamlined workflow.
How to protect your main branch
To protect the main branch in GitHub, you can follow the steps below:
- Go to your GitHub repository and click on the “Settings” tab.
- In the left-hand sidebar, select “Branches.”
- Under “Branch protection rules,” click “Add rule.”
- In the “Branch name pattern” field, enter “main” (without the quotes).
- Under “Require pull request reviews before merging,” select the checkbox.
- Under “Require status checks to pass before merging,” select the checkbox.
- Under “Include administrators,” select the checkbox.
- Click “Create” to save the branch protection rule.
Rails Testing
We have automated deployments so as a developer in a project team or bootcamp I can deploy a feature to production and manually test it as soon as it’s merged. But as our app grows bigger it becomes harder and harder to manually test the entire app and make sure we are not breaking features as we’re building new ones. This is where automated tests come into play; we can write tests and run them at any time to check that the app is working as intended.
My recommendation for putting this into practice given that you don’t have much time to build your projects is to take a “just enough” approach — add the minimum amount of testing required to check that you’re not losing core functionality. For example, test that a key element (that won’t be removed) on each page is visible, so that if you break a page you will know sooner rather than later. This approach doesn’t cover everything but will help you avoid major catastrophes.
Learn More: https://guides.rubyonrails.org/testing.html
In Rails, there are three main types of tests: unit tests, request tests, and system tests. Here’s how they differ:
Unit Tests
Unit tests are used to test individual pieces of code in isolation, such as methods or classes. They are usually fast and don’t require a full Rails application to run. Unit tests are typically written using Minitest or RSpec, and are located in the test/models
directory. They can be used to test the behavior of models, controllers, and other parts of the application.
Example:
# test/models/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "full_name returns first and last name" do
user = User.new(first_name: "John", last_name: "Doe")
assert_equal "John Doe", user.full_name
end
test "full_name returns only first name if last name is blank" do
user = User.new(first_name: "John", last_name: "")
assert_equal "John", user.full_name
end
test "full_name returns only last name if first name is blank" do
user = User.new(first_name: "", last_name: "Doe")
assert_equal "Doe", user.full_name
end
end
Request Tests
Request tests, also known as integration tests, test the behavior of the application’s controllers and views as a whole, by sending requests to the application and verifying the responses. They test how the application responds to HTTP requests, and can help ensure that the application’s URLs, routes, and views are all functioning as expected. Request tests are typically written using Minitest or RSpec, and are located in the test/controllers
directory.
Example:
# test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "index responds successfully" do
get users_path
assert_response :success
end
test "index displays a list of users" do
user1 = users(:one)
user2 = users(:two)
get users_path
assert_select "table tr" do
assert_select "td", user1.email
assert_select "td", user2.email
end
end
end
Run the tests with this command:
$ rails test
System Tests
System tests, also known as end-to-end tests or acceptance tests, test the behaviour of the application as a user would experience it, by simulating user actions such as clicking links and filling out forms. They test how the application works from end-to-end, including its JavaScript behaviour and interactions with external services. System tests are typically written using a tool like Capybara, and are located in the test/system
directory.
In summary, unit tests are focused on testing individual pieces of code, request tests are focused on testing how the application handles HTTP requests, and system tests are focused on testing the application as a whole from a user’s perspective.
Example:
# test/system/sign_up_test.rb
require "application_system_test_case"
class SignUpTest < ApplicationSystemTestCase
test "user signs up successfully" do
visit new_user_registration_path
fill_in "Email", with: "test@example.com"
fill_in "Password", with: "password"
fill_in "Password confirmation", with: "password"
click_on "Sign up"
assert_selector "div", text: "Welcome! You have signed up successfully."
end
test "user receives error message with invalid email" do
visit new_user_registration_path
fill_in "Email", with: "invalid-email"
fill_in "Password", with: "password"
fill_in "Password confirmation", with: "password"
click_on "Sign up"
assert_selector "div", text: "Email is invalid"
end
end
Tests and Github Actions
Even though we have testing that can be run easily with a single command, we need to make sure that this testing is happening automatically and is acting as another line of protection for our main branch. We’re going to automate the tests running on each pull request and merge to main, if the test don’t pass you can’t merge. This means rather than finding out you have a bug in production you will likely find out when the test fails and resolve it locally. This keeps your production environment in the bootcamp more stable and makes debugging easier.
To run tests in Rails with GitHub Actions, you can follow these general steps:
- Create a new workflow file in your GitHub repository under
.github/workflows/
, for examplerails-test.yml
. - Define the trigger for the workflow, such as
push
orpull_request
, and specify the branches to watch.
name: Rails Test
on:
push:
branches: [main]
pull_request:
branches: [main]
3. Define the job for the workflow, which will run your tests in the bootcamp. Specify the operating system and version you want to use, and any required setup steps such as installing dependencies.
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0
- name: Install dependencies
run: bundle install --jobs 4 --retry 3
- name: Run tests
run: bundle exec rails test
In this example, we’re using the ruby/setup-ruby
action to set up Ruby 3.0, and then installing our dependencies with bundle install
. Finally, we run our tests with bundle exec rails test
.
4. Save the workflow file and commit it to your repository. GitHub Actions will automatically detect the new file and start running the tests whenever a push or pull request is made to the main
branch.
Note: You may need to modify these steps based on your specific project and testing needs. You can also customise the workflow further with additional steps, such as running linters or deploying to a staging environment.
Conclusion
Although these tools and techniques take a small amount of time to set up, in the competitive microcosm of a bootcamp you may feel like you’re lagging behind other teams when precious developer time is spent implementing them. However, this will reap huge dividends as your project proceeds as you’ll be spending less time debugging and you’ll have more bandwidth for the important things like figuring out how to improve your platform.