I would start with these:<p>1. Commit hooks that lint code (pylint3, flake8, ...). Code must be clean before it is merged.<p>2. Introduce testing: code must be covered by tests.<p>3. Require documentation: there must exist an independent specification of what the code does, at least from an external point of view: what are the interface contracts.<p>Once you have code that is specified and covered by tests, only then do you have a proper environment for transforming badly structured code that works into better structured code that <i>still</i> works.<p>Other than that, organization of programs is a big topic that requires study of theory. For instance, you could probably rediscover the idea that code should be organized into modules such that the content in a module belongs together, and isn't tightly bound to content in another module. You might not have a name for this but an intuitive feeling for it, which is very good. But if you study software engineering, you will learn about cohesion and coupling directly, so you don't have to reinvent or rediscover the wheel. The cumulative effects of learning material directly add up; you can shave years and years from the time it takes to become competent.<p>I think that the decline in the "Wirthian" languages like Modula 2 has been detrimental. The biggest initial boost that I got in the understanding of structured, modular programming was from programming in Turbo Pascal and Modula 2 in the late 1980's.<p>In Modula 2, you structure the program in modules which have a clear interface and implementation, declared in separate files. Modules declare their dependencies on other modules. From this, the compiler knows all the dependencies. There is no need for any Makefile or dependency generation; you tell the compiler to build the program, pointing it at the main module and that's it.<p>Each module has a block of global initialization statements. The compiler/linker, knowing the dependency among the modules, ensure that these statements are executed in module dependency order: if A depends on B, B's global initialization runs first, then A.<p>When I started coding in C, I realized immediately that this is missing: there is just a <i>main</i> function and after that you're on your own. Moreover, unless you declare your dependencies to the Makefile or IDE system or whatever you're using, or get it to figure them out externally, you will not get correct incremental builds.<p>So I simulated modules by carefully structuring header files, and giving each module a global initialization function, and then call these in some disciplined way, like from one big init function.<p>I later saw (thanks in a large part to open source) that other people's big C programs did things like this. I felt that programmers who had exposure to a language supporting modularity had an edge in understanding the issues and motivation for good organization patterns in C programs compared to those who were just getting randomly burned and improving their approach by trial and error.