This article is part of a series How to Organically Grow your Python Project in which I cover the different steps you will go through when starting a new Python hobby project. The focus of this series lies on not knowing in advance what you want to make and thus not planning the whole project from the start.
In this article I’ll talk about the first steps that I took when starting my Python hobby project. This is a story from my point of view and does not serve as the ground truth. It merely shows that I find it normal that developing anything is a continuous process of refactoring. Write some code, make it work, and improve this later. Nothing will ever be perfect, even less so from the very beginning. So don’t beat yourself up when you know what you’re making isn’t how it is suppose to be.
The first thing I always do is setting up a development environment. There are multiple ways to do this but I’ll stick with my favourite. Conda. I won’t go into details because that’s not what this article is about. In short, create a new environment for your awesome project:
conda create --name py_my_awesome_project python=3.8
Keep it simple and only add packages when you need them. Pro tip, avoid mixing Pip and Conda when installing packages, it can cause conflicts. I suggest to make an alias for the command to activate your environment and put this is your
alias py_my_awesome_project="conda activate py_my_awesome_project"
So from now on you can just type
py_my_awesome_project in your terminal when you want to activate your environment instead of the whole source activate stuff.
I will not discuss what editor to use, which extensions are useful, or how to configure them all for an optimal development experience. Nor will I discuss how to turn your project into a git repository such that everything is version controlled. There are plenty of articles on these topics scattered across the web. Just for the curious reader, I use both Atom and VSCode, I turn on autoformatting on save (with a linter according to PEP8 style), and I find Kite extremely promising. And Bitbucket is my place to go for storing my remote repositories.
Now you are ready to code! Create that
main.py file! The first thing I do is write some code that has minimal functionality. For example make a class, give it some attributes, and some custom methods. Make a few instances of that class and check if they behave as expected. When you are happy, make some more classes and repeat the process. Don’t overdo yourself, don’t overthink naming or structure, you will definitely have to change that anyway. When your project is in a more mature stage, these things will be more clear as by then you will have figured out some convention.
When writing more and more code you will most likely say to yourself “I can separate some chucks of code into distinct pieces of logic.” For example, this can be by separating classes into different files. After applying this refactoring in my own project, I ended up with the files
belts.py, furnaces.py, natural_resources.py, plates.py and of course
I sounds like it’s time to start writing unit tests. Or make the case to continue with Test Driven Development. But I disagree. At this point I think it is too early to write tests since I have no idea if all the code I have written is even useful. I might as well have to throw it all away and start from scratch. So instead of writing tests, heavily rewriting code, and completely rewriting the tests, I prefer to postpone testing until the project is semi stable. Don’t get me wrong, I’m not against Test Driven Development and testing is a necessary building block of a well working application. But we’ll get to that point in a later development stage. So the best thing to do now is add more code, more logic, and more functionality.
Over the next days, your project will have grown quite a bit (mine consisted of 20 small files already). And, just like me, you will have have spend most of the time rewriting instead of adding new code. Which is normal. Continuous refactoring is the key to good development. I cannot stress this enough. You have no idea how many times I renamed the same function. Or how often I restructured some code to eventually return it to its original state. But that’s the development life.
By now your project is at the stage where you might break existing functionality when refactoring or adding new pieces. So it’s time to add unit tests. When exactly to start with testing is rather arbitrary. If you start too soon, you’ll have to rewrite lots of tests. If you start too late, you will introduce hidden bugs that fly under your radar since you have no radar (unit tests). It’s up to you to get a feeling for this turning point.
How to expand your project with a testing setup will be covered in the next article of this series.