For me, it helps to break down a larger piece of software into smaller chunks. And then break those chunks into even smaller parts and so on. Every software program is a collection of small pieces of logic.
Consider a blog, for example. You want to be able to create and edit posts that others can read. Right away you can split the project into admin and public sections. At minimum, the admin will require admin users, a login page, and a section for managing the blog. The section for managing the blog can be broken down into a CRUD (Create, Read, Update, Delete) interface. Creating a new blog post will require a check to make sure the admin user has the right privileges, a form, form validation, and the ability to save to the database. And so on.
The more that you break a problem or a feature down, the more manageable it becomes. It's divide and conquer. Once you've been able to map out your software like this, you can take a look at how different pieces of it interact with each other. Where might you repeat code? What can be abstracted? This should be an iterative process both as you plan and as you write the code itself.
I would recommend figuring out what your minimum feature set is to begin with and implementing that before adding other pieces to it. You'll want to code defensively so that future changes won't be too difficult, but at the same time, you don't want to implement half-features that may never get completed. It's a difficult line to walk between staying flexible and being willing to ruthlessly kill your darlings, to borrow a literary reference. Getting good at that particular balancing act only comes from experience.
And that's what it comes down to, as the other answers have mentioned: experience. The only way to get it is to just start. Don't worry so much about making it perfect from the outset. First make the code work, then make it beautiful, then make it fast.
Also, unlike this paragraph, don't tack security on at the end as an afterthought. You should have an idea about ways your software could be compromised, but as a start, never trust any user input.