I know it feels like a clickbaity title. But everyone that makes a tutorial is making it to try to learn how to do it themselves. Heck, I've been programming for almost 20 years, and I still don't know what I'm doing. All of these tutorials that you read or watch normally dictate what the perfect program structure is or exactly how you should lay out your files. But there isn't a perfect layout for this. I believe fundamentally that the proper way to build your software is to allow it to organically grow. But what does that even mean?
Everyone knows how to build a todo app, but what do you do after that? How do you get better than just writing a todo app? I think this is ultimately because by the time you're building something bigger than a to-do app, your application is growing organically and how do you even talk about or explain that?
I'd like to share some of the rules that I've come up with over the years that have worked for me. I'm not trying to say that there should be laws or that there is an exact science or anything like that. It's just what I've found works for me and hopefully maybe it'll work for some of you as well.
When building an app, maybe you're using Next.js or just plain React, Svelte, or Solid.js, I don't think it really matters. But I've noticed that some of these frameworks use file-based routing and route primitives. And I think whether you're actually using those or not, it's a nice file structure to start with.
Let's say for example, ironically, we're starting with a to-do list.
We can create our shared components in our /lib
folder and then for our to-do list we can just start at /routes/todos.tsx
okay this is great so we have a basic working to-do list now but I actually I want to add special functionality into these to-do lists. I want to be able to edit them and have special functionality when you're editing an individual one like an "assignment" or something
Regardless of exactly what it is, the amount of functionality that I want to add to this feels like it doesn't quite fit in one file.
So I'm going to take this /routes/todos.tsx
file and turn it into a folder And then the file that we had before, I'm going to name it index or page or something, /routes/todos/page.tsx
just something that I want to make sure that I always name the same thing in the future.
Now that we have all this similar functionality grouped together in this new folder named todos
, We can take this individual todo functionality, or task, and we'll just create a file named task inside of the todo list folder. /routes/todos/task.tsx
Now that we have another file named task, we can just put all of the code in here that's specific to this particular task. And now we can just import into the page that's in the same folder already. Now I realize that tasks are great, but sometimes things aren't quite tasks and we want to use notes too. So I'll do some refactoring and move all of the task-specific functionality out of the main page file (/routes/todos/page.tsx
) and push it down into the task file and then I'll create a new note file (/routes/todos/note.tsx
) beside of it and we'll add in all of the special functionality that's specific for notes.
Things are going great! We start getting some users and man do these customers love the new notes functionality that we just added and it's fantastic. Some of our users want more funtionality for notes, they have three main things that they really want to added. So we start working on the new features and building out all of this new code in the notes file. But wait, this notes file is starting to get really big again, and a little unwieldy.
So at this point -- what do we do? Let's go back and start thinking about how we handled that originally with out todos.tsx file. Oh, right! We just make a new folder named notes and we take this big notes move it in there. Notes isn't actually a page though, so we're not going to call it page. We're just going to call it index because it's the root functionality file for notes.
Inside of this new file notes file /routes/todos/notes/index.tsx
, we look through our code and notice that we have a lot of code specifically for functionality that relates to code blocks, and also have quite a bit that relates to quotes. So this is why this notes file is so big! Lets do some refactoring in this notes/index
page and break out quotes and code blocks into their own files /routes/todos/notes/codeblocks.tsx
and /routes/todos/notes/quotes.tsx
respectively.
And here is what our file hierchy looks like at this point
my-todo-app
│ README.md
│ package.json
└─src
│ └─lib
│ │ └─api
│ │ └─components
│ └─routes
└─todos
| page.tsx
| task.tsx
└─notes
| index.tsx
| quotes.tsx
| codeblocks.tsx
I know we haven't really dug into any specific code or even any kind of functionality at. But, I hope that you understand from this short example how the organic growth method would continue to work with you as your codebase get larger and more complex. I believe that code organization and structure is something that should grow and evolve naturally as your project expands. This is why I don't believe there's really any tutorial or walkthrough for building something more advanced than a basic todo app. Beyond the basic to-do app, most programs start looking pretty unique. Refactoring is an intuitive endeavor, and an artistic expression of sorts that you will continue to hone as you keep refactoring and choping up your apps as they grow. Most people just slowly learn that the hard way over time with experience, but I think there are little tricks that you can use to help you get there faster, and this is just one of them.
What do you think? Are you a developer that's been around the block a couple of times? Why do you think there's no intermediate tutorials or software guides anywhere to be found? Do you disagree? Does this help? Was there something that wasn't clear, or would you like to continue to explore dynamic growth?
Let's have a discussion in the comments.
If you've read this far, I really appreciate it. I've worked in a large variety of code bases and I've built many projects from the beginning, as well as helped to turn around some older code bases to get them maintanable and increase feature development velocity.
Top comments (0)