How to think about working in teams, consulting, setting common standards for your code, and finding a balance in the CI.
Oct 28, 2022
Sebastian Witowski is a freelancing Python developer and consultant. He has given over 20 talks at various PyCons and also blogs regularly. In this conversation, we focused on cooperation in developer teams: agreeing on common standards and respecting individual preferences, setting up a well-balanced CI. In the 2nd part (coming next week), we'll talk about his activities in the Python community and his content about developer tools.
Reka: We can find lots of talks and blog posts from you online. But what do you do in your day-to-day job?
Sebastian: I'm working as a Python consultant / freelancer, mainly in web development. Usually, I join projects for a long time and work in small, remote, and distributed teams. In my current team, I hold the role of a lead developer, so I'm also shaping the whole project. Occasionally, I also do consulting for companies. It can be about migrating older codebases (e.g. in R) to Python or setting up CI/CD pipelines.
R: That's very versatile. How did you choose this career?
S: After university, I worked at CERN for six years, and that was pretty exciting. Then I decided to move back to Poland with my wife and to work remotely. That was 2018. Working remotely was not that common yet, but I gave it a try anyway.
I enjoy freelancing, working with different products and projects. This way, I also have the chance to work with companies located wherever, although I'm based in Poland in a small town.
R: How do you like remote working?
S: It's definitely different from working for a company that is located in a specific town. When most of the employees are from the same town, they've probably worked for similar companies.
But when you work with someone from Norway, someone from Romania, someone from Spain, everyone has completely different backgrounds. They all have different ways of developing and managing a product.
It takes more effort to get everyone on the same page. Even about things like how we write comments, which types of docstrings we use.
But also everyone has something to bring to the table. Each time I start working on a new project, I learn a lot from other people, which is a really, really nice thing.
R: You mentioned getting everybody on the same page. Can you elaborate on that? What are the most important things the team should agree about?
S: There are those no-brainer things like using Black for formatting. Years ago, I worked on a project where code reviews often contained comments about single vs double quotes. And we didn't have tools that would pick this up. So reviewers manually put in these comments, and someone had to change their pull request to change the style of quotes. You shouldn't waste time doing that.
The baseline is to start using the tools that are industry standard in Python. Like Black for formatting, flake8 for picking up the common problems, isort for sorting your imports.
When I join a new project, I usually try to figure out: Are they using some tools? Can we improve the code review workflow by introducing some pre-commit hooks or some CI pipelines?
R: Can you tell more about the pre-commit and CI setup?
S: CI is great, even if it can take a while to set it up. I sometimes struggle to set it up in GitLab from scratch, but I can often reuse some template with the usual suspects like Black and flake8.
pre-commit is great as well, and contrary to the CI, it doesn't need to be uniform accross the team. I use several static analyis tools in my editor or pre-commit. Mostly because I don't want to impose those more specific tools on other people.
There are things like code formatting you should all agree about. But then when it comes to other tools, people might have their own opinions. The more senior people are, the more fierce discussions about tools can get ;)
And this is always tricky because I don't want to get into endless discussions. They have been using one tool for five years, I've been using a different tool for five years and we would just waste each other's time. So I prefer to use tools for myself and try to nudge people towards trying them out. For example, during a code review, saying something like I saw this and this. And by the way, I'm using this cool tool that helps spot this.
Sourcery is another no-brainer for me. I have ten years of experience writing Python, and Sourcery still finds simple refactorings that I missed.
R: Where do you draw the line? What should a team agree about, and where is more room for individual opinions?
S: I'm happy with people having different opinions and even following different coding styles. I draw the line at PEP 8 and PEP 257. That's what we should implement straight away.
Beyond that, it's mostly about reaching an agreement with the team. So sometimes we review our CI/CD pipelines and we say, okay, there is this another tool that we could use. And if everyone agrees, or if the majority agrees, we just add it.
Of course, you shouldn't overdo it. At some point, the CI can become noisy, especially if all these checks can also block a merge request.
For example if you have a problem in production and you need to push a hotfix. If a stupid linter tells you, look, you have to move those imports while you have clients who cannot use your product, then you're absolutely infuriated. And you're going to get rid of all the stuff.
So you also have to figure out that balance where all those tools are useful, but they don't get in your way. Of course, you can disable those things and merge the merge request anyway, but the tools should help you.
R: Speaking of overdoing. In the intro of your talk Python Versions and Dependencies Made Easy, you mentioned that you've met both kinds of teams: some who are still in the 90s and some who are overengineered. How would you describe these two extremes? How can we notice if our team falls into one of these categories?
S: A sign of too few tools is lots of discussions during the code review. Especially about issues that could be fixed automatically.
At the other end of the spectrum, we have the teams who jump on every new tool they find. When you have a new tool, it’s usually an evolution of some old tools. It has cool new features and it solves new problems that the old tool doesn't. At the same time, not many of those tools survived the test of time. Let's pick ten tools from the most upvoted HackerNews posts in the past few weeks. I bet in ten years, maybe two of them will still be around.
Also, there will be some bugs and corner cases and some things that the tool won't do for you. And if it's a new tool, you don't have people who have experience with that so we can't really compare these to some other tools.
So what I learned some time ago is to strike a balance. And the talk that you mentioned shows three tools that I use almost on all my projects: pyenv, virtualenvwrapper, and pipx. They have been working for years. They will still work for years in the future. I've also been using pip-tools since I don't remember when and I think it will still be supported in the future.
These are also tools that do one thing. You could instead choose a tool that does a lot of things like Poetry, which is, of course, a pleasure to work with. But I prefer this Linux-style philosophy where you pick up a tool that does one thing, but does it very well.
R: What are the advantages of this kind of focused or scoped tools? Why do you prefer them?
S: Because you can easily mix and match them. They tend to produce text-based output that is easy to combine with other tools. For example, pip-tools creates a list of dependencies that can be just read by pip. This compatibility is very handy: if something breaks or I need more advanced features, I can introduce a new tool without changing the whole workflow.
R: What are your strategies to transfer some lessons & best practices from one project to another one?
S: I like having some kind of regular technical discussion. It's good to give developers a chance to discuss things that they find interesting. Or discuss some pain points that they are facing. Some companies do a round of lightning talks within the company. That works really well.
Currently, my team uses a custom commercial framework. And when we struggle with something, it often turns out that another team member ran into the same issue two days ago. So it's nice to have a periodic meeting where people can share their knowledge, ask about things and so on.
Screen sharing and pairing sessions also work really well. You can notice if others use a new tool, recommend some setups and so on. The more people interact with each other, the better it is for spreading knowledge.
We can also always document things. But for me, documentation alone never worked that well for knowledge sharing. It's much better to have a discussion or a demo and regard the documentation as complimentary.
Documentation is helpful for answering specific questions, but not for discovering new stuff. If you don't know something is possible, you will never think about searching for it.
R: How do you share your knowledge when you have the role of a consultant?
S: You really need to understand what problems the company is facing. Usually, the people who reach out to you are higher in the hierarchy. And sometimes they say “we want you to fix this”. And when you start talking to them, it turns out that the underlying problem is completely different. So you need to spend some time discovering the real problems.
The way of communicating possible solutions also matters a lot. You can't force some strangers to do things your way. Or tell them that we're just scrapping your whole workflow. It's important to convince people with benefits and try to address the pain points they're facing.
I can tell them “this is how some other companies do this”. Or “this is what you can do to make it more efficient” and so on.
R: Do you have some strategies for this?
S: It definitely helps to prepare very well on the first meeting. And to talk to multiple people from the organization.
You have to take good notes and often get back to them to verify that you understood everything correctly. Especially before you start creating a roadmap. If you've misunderstood their problems and their expectations, you're basically wasting time and the client is not gonna be happy. So you have to be very thorough with your communication.
R: What are usually the situations when a company hires you for such an ad-hoc consulting?
S: A frequent case is when companies want to migrate an older project (for example in R) to Python. And I help them figure out which packages or tools they need to reproduce the same stuff.
Sometimes, companies struggling with tooling reach out. Or they have spaghetti code. And they would like to figure out how they can reorganize their project and how some tools can help get all their developers on the same side.
R: I'm surprised by the spaghetti code topic. I would assume that several companies have this issue, but only a small part recognizes it.
S: That's a good point. Like, companies don't recognize this often as a problem. I think I've had only one client that asked explicitly for that.
Most of the time, it just comes up as part of a different request. Usually, companies don't want to spend money to tackle a technical debt. They don't care how their code looks like as long as it brings the money. Only when there are too many bugs to fix and it takes too long to implement new features. That's when they think maybe we have to invest in someone to help us with this.
R: What are the first steps? How will you start paying back this tech debt?
S: It's always nice to have some tests. Usually, companies that have messy code, don't have tests. That's the main problem. If you have enough tests, you can rewrite parts of the code and make sure everything still works.
So, the first steps would be to add some happy path tests to the old codebase. Then you will have at least some level of certainty that after you do the migration, it still works.
Then you have to sit down and talk with developers and try to figure out: Have I understood what this project does? As a consultant, it's an additional difficulty that you don't know the project well. It's a bit easier if you're in a team and you internally decide that you want to reduce your technical debt.
For example, in the project that I'm currently working on, we accrued some technical debt, and we obviously didn't have dedicated time to tackle this debt at the beginning. So the idea was to use the "boy scout" method that whenever you're working on a new feature, try to refactor a bit of this code. Maybe extract some things. Maybe create a small new module. This is a really nice approach if you can't devote a lot of time to refactoring. And suddenly, after like a year of all the developers doing this, you get much less technical debt.
This approach is much easier to sell to the business users. Because if you tell them, look, I need a week to rewrite this, they will hear “I’m gonna waste a week doing something that won’t result in any new features”.
So instead, you can say “I need two days to implement this feature because I need to write a test and I need to make sure everything works”. Then you spend one day writing the feature, a second day adding some tests.
R: Do you also recommend this step by step approach in your consulting?
S: As a consultant, it's more about creating a roadmap. A big difference is that I won't be there to write the code myself. So it's rather about figuring out what's not working now, what's the main problem, how their ideal solution would be. Or if they could solve their one biggest problem, what would that problem be?
Maybe you show them what could be a reasonable way to structure things: create some test folders, use pytest, conftest.py for the fixtures and so on.
It's often about showing them some possible tools that could make their life easier. They might not like some of them, but they might discover something very useful as well.
R: What other technologies do you use besides Python?
S: Most of my client work is in Python. In a project two years ago, I used a bit of Vue.js, and that was fun. Right now, everything is Python, because we have this framework that also generates the React frontend from Python code.
When I have time for some side projects or hobby, I try to use different stuff. For example, I've built my personal website with 11ty JavaScript is here to stay, so even though I'm using it from time to time and I always have to remind myself how to write a for loop, I still try to keep my knowledge up-to-date.
I want to learn Rust. But I've wanted to learn Rust since, like, I don't know, over a year. I looked at some tutorials, and it seems to be really nice. Also, the tooling is great. That's a huge advantage of this language.
I didn't study computer science. When I was studying automatics and robotic control, I had C in the first semester and then two semesters of C++. And it's great to know C and C++, because some principles stay with you, but that's not how you get people interested in programming. People don’t get hooked up on programming because you show them pointers.
My first semesters with C and C++ felt quite like a waste of time. Then in the last semester, I forced myself to learn programming, because I thought that could be useful. So I learned just enough C++ to do the basic stuff.
But then later, I started building websites, and this I enjoyed really much. With a website, you change a bit of CSS and immediately, your website changes colors. You don't have to go through, like, fifty compilation errors to see the results. And that I found fascinating.
This is the first part of our two-part interview with Sebastian Witowski. Stay tuned for part two, which we’ll be posting shortly.