Study design patterns. The definitive guide, Design Patterns: Elements of Reusable Object-Oriented Software, is a good place to start.
Also study anti-patterns, which are common solutions that end up being counterproductive to the problem are meant to solve. There is much written about both patterns and anti-patterns.
Get proficient with tooling: graphical debuggers, unit testing frameworks, static type checkers, linters, scaffolding tools, build automation tools, source control. Tooling makes the difference between a coder and software engineer.
Learn functional programming if you don't already know it (shameless plug but functional programming is awesome).
Siddarthan Sarumathi Pandian
Full Stack Dev at Agentdesks | Ex Hashnode | Ex Shippable | Ex Altair Engineering
It's a very gradual process. I think if you're already working, a good way to learn is through code reviews. Push your mentors/colleagues to review your code and try to grasp what they tell you. Also, watch their PR's actively and try to learn from them.
If you're not working or actually, even if you're working, the best way to learn to write good code is to look at the code that good programmers write and you can usually find them in most open source projects.
So, pick a popular open source project of your choice in the language you like and try to read the code. Try to understand the standards and patterns they've in place.
It can be intimidating to get started with, so as a first step you can look at small pull requests that got merged recently to the project. :) And with time, you can start reading the code base and eventually start making PR's to these projects as well.