This is part two of a three-part series on building development teams. I was inspired by Matt Stauffer’s Laracasts talk, and I’m adding my own experience as a developer and team lead. In Part 1, we talked about culture, hiring, and team structure. Here we go deeper into how the actual work gets done.
Processes should serve developers, not the other way around
There’s a pattern I’ve seen in many teams. Something goes wrong. A bug reaches production. A deadline is missed. And the response is: let’s add a process.
Now there’s a new daily standup. Now commits must be linked to Jira tickets. Now every pull request needs three approvals. Now there’s a weekly report. And another meeting.
Each of these things was created with good intentions. But together, they add up to hours every week where developers are not actually developing. They’re feeding the system.
The goal of any development process should be simple: help developers write and ship good code. If a process doesn’t help with that, it should be removed or changed. Full stop.
This doesn’t mean having no process. It means being intentional about every step you add, and being willing to question it when it stops helping.
Start with Git - there’s no real alternative
If you are not using Git for version control, start there. Today.
Git is not just a tool for large teams. Even a single developer benefits from it. The ability to track changes, revert mistakes, create branches for experiments - these things matter whether you are one person or one hundred.
For hosting your Git repositories, the answer is GitHub. I know some people prefer GitLab or Bitbucket. But GitHub has the best pull request workflow, the best integrations, and the largest community of developers who already know how to use it. The few dollars you might save by choosing something else are quickly lost in friction and missing features.
A branching strategy you can actually follow
When your team starts working with Git, you need to agree on how you use branches. There are complex strategies out there (GitFlow, for example) but most teams don’t need that level of complexity.
Here is a simple setup that works well for most projects:
main- this is your production branch. It deploys automatically to your live server. Only stable, tested code goes here.develop(orstaging) - this is where active development happens. It deploys automatically to your staging environment. Things might break here occasionally. That’s fine.- Feature branches - short-lived branches for individual features. They get merged into
developwhen ready. They should live for days, maybe a week or two - not months. - Hotfix branches - created from
mainwhen something breaks in production and needs an immediate fix. Merged back into bothmainanddevelop.
The key principle: merging to main is how you deploy to production. Merging to develop is how you deploy to staging. Everything is automated. Nobody should be manually deploying by copying files.
Write commit messages like you’re leaving notes for a future colleague
Most developers treat commit messages as an afterthought. fix, wip, changes - these tell nothing to anyone who looks at the history later.
Good commit messages describe what the change does, written in the imperative form: “Add login with GitHub OAuth”, “Fix pagination on the users list”, “Remove deprecated payment provider.”
Think of your commit history as a timeline of decisions. When something breaks six months from now, that history helps you understand what changed and why. When you write wip for the third time in a row, you’re making that future investigation much harder.
One useful rule: a commit should be large enough to represent a meaningful change, but small enough that you could roll it back on its own if needed. Not two lines that do nothing by themselves, but also not a massive dump of everything you changed this week.
Pull requests: two sets of eyes before anything goes live
Every piece of code that goes to production should be seen by at least two people. Either two developers pair programming, or one developer writes and another reviews.
Pull requests are the main tool for this. A good PR has:
- A clear description of what changed and why
- Screenshots or recordings if there are visual changes
- A small enough scope to be reviewed in a reasonable time
Keep PRs open for days, not weeks. The longer a branch lives in isolation, the harder it becomes to merge. Other changes pile up in develop, conflicts grow, and eventually you’re spending more time on the merge than on the original feature.
Code review is not about being the boss. It’s about catching things one person missed, spreading knowledge across the team, and maintaining a shared standard of quality.
One thing I’ve noticed: developers often improve their own code just by writing the PR description. Explaining what you did forces you to think about whether you did it right.
Define your coding standards early
Every team argues about code style at some point. Tabs vs. spaces. Where the brackets go. How to name variables. This is what’s called “bike-shedding” - spending time on small, low-stakes decisions instead of the real work.
The solution is to make these decisions once, document them, and automate the enforcement.
For Laravel teams, tools like PHP CS Fixer or Pint handle most of this automatically. You configure them once, add them to your CI pipeline, and the linter tells you when code doesn’t follow the standard. No more arguments in pull requests about formatting.
Beyond formatting, document your higher-level engineering standards too: how do you structure feature code? When do you use caching? What’s the minimum expected test coverage? These decisions should be written down somewhere that new developers can read on their first week.
CI/CD: automate the boring parts
Continuous Integration means your tests run automatically every time someone pushes code. Continuous Deployment means code gets deployed automatically when it’s merged to the right branch.
If you’re not doing this, you’re spending human time on things a machine can do better. Running tests manually. Deploying by hand. Checking if something broke.
Set up CI to run your tests on every pull request. Set up CD to deploy develop to staging and main to production automatically. Now the workflow is: write code, open PR, CI checks pass, merge, done. No manual steps.
There are two other tools worth having on every project:
Exception tracking (like Sentry, Flare, or Bugsnag): this sends you a notification when something breaks in production. Not a user filing a bug report - an automatic alert the moment the error occurs. Pipe these notifications to a Slack channel so the whole team sees them.
Mail testing (like Mailtrap): staging environments send emails. You don’t want those going to real users. A mail testing tool catches all staging emails in one place so you can preview them safely.
Paper cuts: small things that waste large amounts of time
A “paper cut” is a small annoyance that doesn’t seem like a big deal on its own, but adds up to real cost over time.
Slow tests. If your test suite takes 10 minutes to run, developers stop running it locally. They push code and wait for CI. When CI fails, they fix it and push again. More waiting. The feedback loop stretches from seconds to hours. Fast tests are not a luxury - they’re necessary for a productive workflow. If your suite is slow, invest time in fixing it.
Long-running pull requests. A PR that’s been open for three weeks means a branch that’s drifting further and further from develop every day. The merge gets harder. The review gets harder because there’s too much to look at. Merge early, merge often.
Outdated dependencies. Using old versions of packages means you can’t use new features. It means you’re looking at outdated documentation. It means security vulnerabilities pile up. Updating dependencies is boring work, but letting them fall behind is more expensive in the long run.
Kanban over Scrum: keep it simple
When it comes to task management, I’ve tried various systems. My recommendation: Kanban with a simple weekly cadence.
Here’s what this looks like in practice:
Once a week, you meet with the client or product owner. You show what was done last week. You agree on what to work on next week. You ask any questions you have. That’s it. The meeting is short.
In between meetings, developers pull tasks from the top of the “To Do” column. When a task is done, they move it to “Done.” There are no sprints. No story points. No planning poker. No velocity charts.
Kanban boards have columns that represent stages of work: To Do → In Progress → Ready for Review → Done. Cards move left to right. Priority is shown by vertical order within a column - top cards are most important.
Why not Scrum? I’m going to say something that upsets a lot of consultants: Scrum, as it’s usually implemented, is more useful to managers than to developers. Sprint commitments, velocity targets, burndown charts - these create pressure and overhead without improving the quality of the work. They optimize for the appearance of progress, not actual progress.
The Agile Manifesto - the original document, not the consulting industry built around it - is genuinely good. It talks about delivering value continuously, welcoming changing requirements, and trusting your team. Those ideas are worth following. The heavy process that gets sold as “agile” is often the opposite of what the manifesto intended.
Keep it simple. If something isn’t working, change it. Don’t add complexity until you have a real problem that complexity will actually solve.
Write good task cards
A task card should contain enough information for a developer to start working. Not a novel. Not a vague three-word label either.
For a developer who knows the codebase and understands the product, “Allow users to log in with GitHub” might be enough. For a developer who is new or for a feature with specific constraints, you might need a few more lines explaining the expected behavior.
The goal is to be as minimal as possible while still being clear. If a card takes more than a week to complete, it’s probably two cards. Split it.
Cards should come from a conversation between the product owner and the technical lead. The product owner explains the “what” and “why.” The technical lead splits it into things that make sense to build in sequence. Neither should do this alone.
Give your developers room to make decisions. If you hire capable, experienced people, they can figure out the best implementation. You don’t need to spec every pixel. Trust them with the how, and stay clear on the what.
On estimates: be honest about what you don’t know
Clients and product owners always want to know how long something will take and how much it will cost. This is a reasonable human desire. The problem is that software estimates are almost always wrong.
The reason is simple: we never know less about a project than on day one. We’ve never built this exact thing before. Requirements change. Unexpected complexity appears. Things that seemed easy turn out to be hard.
This has led to a movement called #NoEstimates, which argues that estimation is not just inaccurate but actively harmful - it creates pressure, burns out developers, and leads to cutting corners when the deadline approaches.
My practical position is somewhere in the middle.
When it’s possible, I try to avoid giving estimates. Instead, I suggest: let us show you what we can do in two weeks. Then you’ll have real data on how fast we work. Most clients who agree to this stop worrying about upfront estimates quickly, because they can see progress.
When an estimate is truly unavoidable - for grant applications, for budget approval, for certain contract types - I give what I call a “ballpark.” Not a promise. A reference based on similar work we’ve done before. I make it clear in words, and in writing if necessary, that this is not a commitment. It’s a rough guess based on past experience.
The best answer when someone asks “how long will this take?” is often: “I’ll know more after the first week of work.” That’s honest. And it’s actually true.
The short version
Good development process is mostly about removing obstacles. Use Git and GitHub properly. Automate your deployments. Set coding standards early. Keep tasks small and clear. Avoid the complexity of Scrum unless you have a very good reason. Be honest about estimates.
The best process is the one your team actually follows, not the one that looks impressive on a whiteboard.
In Part 3, we’ll talk about managing people day to day: growth, performance issues, finances, and the tricky relationship between the dev team and the rest of the company.