Concurrency can be hard without the right primitives. Queues, Observables, and actors can sometimes help a lot.
Premature optimization is the root of all evil. A good general development process is: 1) Get it to work. 2) Make the code beautiful. 3) Optimize.
Know your basic data structures and understand time complexity. It’s an effective way of making your code much faster without adding complexity.
Practise back-of-the-envelope calculations. How many items will a piece of code generally hold in memory?
Write code as you want to read it. Add comments where you think you will not understand your code in a year’s time. You will need the comment in a month. Somewhat related;
Setup your build tooling around a project so that it’s easy to get started. Document the (few) commands needed to build, run, test and package in a README file.
Making sure your projects can build from command line makes things so much easier down the road.
Handling 3rd party dependencies in many languages can be a real mess (looking at you Java and Python). Specifically, when two different libraries depend on different versions. Some key things to take away from this: 1) Constantly question your dependencies. 2) Automated tests can help against this. 3) Always fixate which version of a 3rd party dependency you should use.
Popular Open Source projects are a great way to learn about good maintainable code and software development process.
Every single line you add to an application adds complexity and makes it more likely to have bugs. Removing code is a great way to remove bugs.
Code paths that handles failures are rarely tested/executed (for a reason). This makes them a good candidate for bugs.
Input validation is not just useful for security reasons. It helps you catch bugs early.
Somewhat related to above: State validation and output validation can be equally useful as input validation, both in terms of discovering inherent bugs, but also for security sensitive code.
Code reviews are a great way to improve as a programmer. You will get critique on your code, and you will learn to describe in words why someone else’s code is good or bad. It also trains you to discover common mistakes.
Learning a new programming language is a great way to learn about new paradigms and question old habits.
Always specify encoding when converting text to and from bytes; be it when reading/writing to network, file, or for encryption purposes. If you rely on your locale’s character set, you are bound to run into data corruption eventually. Use a UTF character set if you can get to choose yourself.
Know your tools; That includes your editor, the terminal, version control system (such as git) and build tooling.
Learn to use your tools without a mouse. Learn as many keyboard shortcuts as possible. It will make you more efficient and is generally more ergonomic.
Reusing code is not an end goal and will not make your code more maintainable per se. Reuse complicated code and be aware that reusing code between two different domains might make them depend on each other more than necessary.
Sitting for long time by the computer can break your body. 1) Listen to what your body has to say. Think extra about your back, neck, and wrists. Take breaks if your body starts to hurt. Creating a pause habit (making tea, grabing coffee) can surprisingly be good for your body and mind. 2) Rest your eyes from time to time by looking away from your screen. 3) Get a good keyboard without awkward wrist movements.
Automated testing, and in particular unit tests, are not just testing that your code does what it should. They also 1) document how the code is supposed to be used and 2) also helps you put yourself in the shoes of someone who will be using the code. The latter is why some claim test-first approach to development can yield cleaner APIs.
Race conditions are surprisingly more common than one generally thinks. This is because a computer generally has more TPS than we are used to.