PREPRINT
Software Development in Small Teams
A little bit of background: This article reflects my experience as Tech Lead and de-facto software project manager at a small company. If you're in a similar position, you know that it's quite common for technology heavy startups to punch way above their weight. I've outlined how this can be done effectively and without resulting in failed projects or dissatisfied team members. For more credentials, click here.
Contents
- Problem Statement
- Proverbs (tl;dr)
- Explicit DONT'S
- Software Development Practices
- The Team
- Project Management
- Communication
- Lean Tech Stack
- Tooling
- Further Reading
Problem Statement
So you find yourself spearheading the software development department at a small company. Good job, you have made it. Let's say that you have got up to three other software engineers in your department. Now, one day the CEO of the company wants to introduce a new "feature". Nothing groundbreaking, just little functionality here and a few tweaks there. After some initial research, it turns out that this small feature is, in fact, a standalone service with its own database, integration tests, will be required to hit close to real time latency requirements, has a customer facing frontend and will of course require its own deployment. If this sounds vaguely familiar: Congrats, this article might be just for you.
Proverbs (tl;dr)
Want a quick overview of my preferred approaches and got no time for a full article? Just read section.
Your role as "Lead" (whatever your actual job description might be), is to guide the software department through uncharted territories, as well as already well known problematic waters. As you're already aware of, software development does not actually stop once the product is delivered. It needs to be continuously maintained and improved. So, software must be properly thought through and kept maintainable for an indefinite amount of time. You never know how long your project will actually be used.
The following proverbs have proven me well and I am strongly convinced that these rough rules form the basis for getting projects done properly:
- Keep your devs happy and motivated
- Communicate goals regularly to the team ("Sprint" planing & Long term goals)
- Developers should "own" the product, i.e. feel like it is their own project
- Embrace the ideas of your devs
- Clear is better than clever - Dave Cheney
- Automate as much as possible (as long as it does not take more time than it saves)
- Plan for the future; proper foresight & architecture is key
- Eliminate communication overhead (direct communication between stakeholders and developers)
- Have specialized "Full Stack" devs
- Reuse code (create modules / templates / packages)
- Use existing technologies
- Containerize your software where it makes sense
- Backup often (repos and machine snapshots, diffs / full backups)
- Fail Fast (and have safety nets)
- Focus on the minimal viable product, optional features can be added later
Sounds quite simple, right? Well, project management isn't exactly rocket science (except if you're building a rocket). That said, you've probably already worked with teams that did not follow these (or similar) proverbs. Did they manage to produce a proper product in an acceptable amount of time, while keeping devs happy?
Explicit DONT'S
The Proverbs stated above form very rough guidelines for projects to head in the right direction. There are also indicators if the project or management style is flawed. If one or more points of the following list fit your projects description, you might be in for a bad time:
- Projects have more non-technical staff than actual devs
- It takes more time to "plan" (by non-engineers) and "get permission", than is spent on actual software development
- Your product has an overly complicated architecture (most applications do not need to consist of more than 3 components [App / DB / UI])
- You’re using blockchain technology
- A non-technical person makes technical decisions
- The team lead / project manager / software architect has not worked on software for many years (or never)
- Management ignores pleas from technical staff
- Poor project management
- Waterfall model for projects quickly changing requirements
- Very large tasks (with no real approach on how to solve them)
- Sequential tasks assigned far into the future
- Aggressive application of SCRUM (more time spent on the process, as opposed to actual work)
- No backups plans (staff and data)
- Consultants from big players are hired to help you with technical decisions
Software Development Practices
Proverbs on how to guide your team through the software development process have already been stated, but what about some concrete 'hard' software development advice? What about style guides for code and the best programming language for the job? As many things, these points highly depend on your team and objective. Some general software development best practices that are programming language agnostic:
- Use feature branches The Gitlab Flow version control workflow should by read and understood by your team. Also have a look at branching workflows as described in the Pro Git book.
- Have Development, Staging, Production Environments
- Prioritize code quality and readability above all else.
- Tag releases
- Add issue references to your commit messages (GitLab, Github)
- Do not use a hammer when wanting to drive a screw
- Use the right tool (language), for the right task (project)
- But also don't adopt 100 different languages because you think they are the right tool
- Don't reinvent the wheel, but also do not hop on the latest trends and switch libraries every other month
- Refactor and cleanup often (gradually build a better product)
- Test what actually matters, coverage does not say a thing about test quality
The Team
All these guidelines and proverbs are well and good, but won't actually get work done without the most important part of any project: The Team.
When trying to tackle big projects with small teams, a huge factor that determines your success will be the skills of your team. In stark contrast to large companies with armies of programmers to tackle a single problem, you'll probably have to deal with one to five software engineers for big projects. Very similar to RPGs, your team should consist of people that are generally well skilled and have niche skills in specific areas.
To once more reiterate the following point: A team without capable members, or members that are unwilling to learn is bound to fail. Having personally experienced teams where skill was a rarity, or has been highly held back by the process / project management, trust me: If you find yourself in such a team, leave sooner rather than later for your own sanity.
I am convinced that giving team members meaningful tasks is key. That means that devs must know why this feature is required, even if the implementation of the feature is annoying or very difficult.
Fields of Expertise
We've already established that you're probably a dev or a lead at a small company. You will be expected to take on a broader range of responsibilities than engineers in larger companies. Being an ace of all spades is key, but not an easy thing. Make sure to organize your team well (have experts in different fields) and support them if they want to broaden their knowledge. Each developer has their own individual technical strengths and academical knowledge. Embrace their skills (e.g., CI/CD work) while keeping them informed about all other technologies in use.
Every developer should be able to fix major parts of the applications, even if he has not actively worked on this specific part for a while. Sharing project and field-specific knowledge is important to keep the team on the same page. If SHTF and a key team member is on holiday or sick, the team must still be able to solve the problem at hand. This can be achieved by creating a knowledge base in the form of wikis (BookStack, GitLab, GitHub), READMEs and other forms of knowledge bases (Zettelkasten, Obsidian).
"Free Friday" / "Creative Friday" projects have also proven to be a very effective tool to broaden and deepen the skills of teams. "Free Friday" projects means that the team is encouraged to spend time on non-business-critical projects, on specific days of the week. For example:
- Team Member A has always wanted to look into FluxCI for GitOps.
- Team Member B has some ideas on how to implement an embedded controller, to trigger the coffee machine over HTTP.
- Team Member C wants to get better with Jupyter Notebooks and creates some plots regarding time spent on drinking coffee per project.
These projects might seem silly at first, but have two key positive aspects: Team members are kept happy, because they can work towards their own goal. Team members learn new technologies and are encouraged to present their work to other members at the end of their project.
Project Management
I'll start by saying the following: Project Management is not something you will start out doing. Especially for startups it is very common to have no project management in place at all. This is not inherently bad, as it keeps the initial development cycles quite lean. Eventually though, as more and more people join the team, project management will gain in importance.
Startups and companies of all sizes are often tempted to hop on to the latest trend. So, when buzzwords like SCRUM and Agile are thrown around, entrepreneurs and engineers alike will be tempted. Project management relies heavily on your team and project specific requirements. You will need different project management strategies when developing software for NASA, then when creating a cross-platform calculator app.
The main objective is always the same: Teams need structure, projects need to be properly planned. The crucial point to keep in mind is the following: The project management process should not hinder actual work on the project. Take ideas from different approaches, i.e. story points and sprints, discuss them with your team and try working with them. If these ideas don't work for your team, rethink your process don't make your team fit the process.
With that out of the way, the following ideas have worked well for our team: Keep in mind that our team already works very well together. One main reason for this is that I've known my main development partner for a very long time and thus both of us know exactly what the other person is capable of. The chemistry in your team will be different.
1. Developers Own the Product
Project management can be perfect, but the project will fail if the most essential part of the process is not motivated: the developer. Inclusion of the engineering team in the planning process is crucial. They will provide crucial input, that might have otherwise been missed. It also streamlines communication as they are not commanded from top down on what to do, but are actively participating in the planning.
Another crucial point is the following: If an engineer comes up with an idea on how to improve existing projects, or do something completely new, do your due diligence if this idea actually makes sense (see Free Friday projects above). If so, give the engineer authority to implement his idea. This, of course, has to fit into existing time constraints and deadlines, but will result in great software developed by happy engineers.
2. The best meeting is no meeting
Have as few meetings as possible, period. Whenever meetings are actually necessary, they must be as concise and short as possible (talking shop). Attention spans degrade rapidly during meetings. If the most technical stuff is discussed last, the meeting has probably not been set up or moderated properly.
3. Keep goals small
Avoid making strict plans for the next quarter of the year. If you decide to "sprint" make the sprint goals achievable. In our case, sprints are considered more of a todo list, so there is no rush to finish all tasks until the end of the sprint. We work on multiple wildly different projects at the same time and having a quick and easy overview of what should be done next is key.
4. Split / define work packages well
This depends on the seniority and skill of your developers. Defining a "silver bullet" ticket might not be a good idea, for new developers that might not be very familiar with your architecture and guidelines. Even for more experienced engineers, it makes sense to break up big tickets into smaller issues, which are all well-defined (and preferably independently testable).
Defining ticket scopes and estimating the time a ticket might take is a very hard problem to solve. Time estimations will be wrong, scopes will change. That said, plan tickets with field experts and a tech lead. When estimating time and effort or story points, the person that actually works on the issue should provide the most input.
5. Have a clear big picture
Projects will inevitably get sidetracked, make sure every team member sees the big picture and knows which steps are needed to get there. It is also important to keep track of your tasks. As already mentioned, tasks / issues / features / scopes will constantly change and shift. Make sure to identify mission-critical tasks and roadblocks early and account for them in your planning.
6. DO NOT reinvent the wheel
If you're in the research phase of a new project and discover that well-established industry-standards already exist, it probably makes sense to go with the existing software (as long as all requirements are met).
7. Reevaluate decisions
As mentioned numerous times, scopes will change, mistakes are going to happen. Don't be too proud to admit mistakes or to pull the emergency break on a poorly planned projects.
Communication
Keep management in the loop. Software development can often be very "elusive" as non-engineering staff has absolutely no idea what the actual Linus developers do. Management most likely does not consist of elite software engineers. Make sure to communicate important issues in a timely manner and regularly reiterate why issue XYZ must be tackled. The following rule of thumb is quite true in my experience:
If you can explain to your mother what you're doing (say building a chat application), management can most likely follow and understand what you're working on. If you are unable to explain it to her (i.e. building a new authorization layer on top of OpenID), management won't understand either.
Software can be a bit similar to atomic radiation; it cannot be heard, touched or tasted. Thus, software is given little thought by non-technical staff. Make sure they know you're there for a reason.
A good communication skill to learn is the following: First listen, then talk. Listen to your Co-Engineers, higher ups and other staff. Software (and OPs) should make the lives of other employees easier, not overcomplicate them. Do not dismiss input from non-technical staff. They are the ones using your software every day. They are the first to encounter bugs or usability problems.
Un•gustl - Austrian slang for a pretentious / despicable person Be humble, just in general. No amount of credentials or experience in any field justifies being a "Ungustl".
Lean Tech Stack
Software development proverbs have been outlined previously, this section is going to discuss how they are actually implemented.
One of the main goals to strive for is simplicity. Yes, I know writing complex code with the latest templating magic, macros, tons of inline loops and of course a turing machine in Regex might seem alluring, but keep in mind: Complexity kills maintainability. If code is simple, it requires less cognitive resources by the developer that tries to work on it. Less complex code also has the advantage of being less prone to bugs.
As presented by Rob Pike in 2015 at dotGo:
- Readable code is reliable code.
- It's easier to understand.
- It's easier to work on.
- If it breaks, it's easier to fix.
The tech stack highly depends on the skill-set of your engineers. If none of your engineers have proper knowledge on how to run and manage Linux servers, it is probably not the best idea to set up your own cluster on bare metal servers. Some consultant suggests you set up a Kubernetes cluster for a static website, with 100 daily visitors, because it is the hot new thing? Management talks about implementing AI to use in your very sophisticated barcode label printing program? Well, as previously already mentioned: Complexity kills maintainability. Making your tech stack or program artificially more complex will result in a worse end product that nobody wants to work on.
That said, leveraging tools from big players is a must for small teams. Firebase Authentication / Google Identity, GitLab CI/CD & Registries, et cetera, are all products that can immensely help projects, without much associated cost. When using third party tools, keep in mind to not lock yourself in. Vendor lock-in Vendor lock-in Describes a situation where the customer is dependent on a vendor for products and unable to use another vendor without substantial switching costs. can pose a very real problem once your application starts to scale. Completely relying on serverless cloud computing code, that cannot be locally debugged, might not be the best idea for your bank transaction application with 10.000 requests a minute.
Let's get down to some actual technical recommendations. It is extremely important to start working towards the goal your application should achieve and not spend most of your time fighting the tooling. For small to medium scale projects (100–500.000 requests per hour) I prefer the following tech stack:
- traefik (Routing / Load Balancing / TLS)
- Docker in Swarm Mode (Orchestration + Scaling)
- Keycloak (Authentication / Authorization)
- GitLab CI/CD or GitHub Actions (Pipelines and Container Registries)
- GoLang / .Net / Kotlin (Micro)services
- Split along logical and application boundaries
- i.e. User Service handles all user interactions vs Inventory Service handles all things inventory
- Each service has its own project, CI/CD pipelines and DB / persistance layer
- Just use a proper server language, interpreted langs have other places
- Prometheus, Grafana, .. (Monitoring)
JaegerOpenTelemetry (Telemetry, Tracing, Logs)- Professional multi instance hosting
The wonders of CI / CD
CI/CD pipelines can not only be used to deploy containers to vServers, they can also be used for periodical schedules (run BI tasks), to upload software, run daily backups, et cetera.
Learn how to properly facilitate pipelines, and small development teams will cut their time spent on manual overhead at least by 80%. Automate everything, as long at it does not take up more time than it saves.
If pipelines are set up properly, developers (with the correct permissions and proper review) can directly deploy from their IDE and waste less time on manual overhead. Reuse pipeline tasks with templates in other projects to keep overhead minimal.
With increased computational load required by more extensive CI/CD pipelines, premium plans (with more compute minutes) or self-hosted CI/CD runners will be required. Self-hosting runners is great, as you're able to equip the runner's host machine with as much power as needed.
(Crazy) tales from the world of pipelines:
- Test, cross compile ARM software on x64 runners and deploy directly to embedded hardware
- Long running data mining tasks over night
- Spin up entire clusters to run integration tests in
- Set up a pipeline step to register REST routes with your identity provider
Tooling
Teams should have proper tools at their disposal. A carpenter cannot work without a proper hammer. The same goes for a software engineer, the quality of the end product will suffer, if no proper tools are supplied. Developers have their own preferences and will have strong opinions on what tools they want to use.
We've tried many tools and most often than not come back to the following tools:
- GitLab / GitHub
- IDE of developers' choice
- Jetbrains products
- VSCode
- neovim
- Stable Linux distro of choice
- Docker / Podman
- Keepass
- Coffee ☕ ☕ ☕ (Seriously.)
If you're not familiar with Linux and don't know where to start, have a look at my post about software recommendations.
Closing Remarks
If you've made it this far, thanks for reading. I hope this article gave you enough knowledge to tackle big projects with a minimal number of hands. If you would like to comment, feel free to contact me through the channel of your choice. Also, I would like to thank my great team at Hoss Mobility. ♿
Further Reading
- Kory Kogon et al. - Project Management for the Unofficial Project Manager
- Mark Richards et al. - Fundamentals of Software Architecture
- Martin Fowler - Great blog about software architecture
- Dave Cheney - About Go and good code
- NASA - What made Apollo a Success
- Diane Vaughan - The Challenger Launch Decision
- The Primagen - SW development at big companies (take with a grain of salt)
- Golang Dev Resources - Extremely valuable insight into programming in general