3 ms·
Your last paragraph is really interesting to me. It obviously makes total sense. Yet, three environment I've used most in my career is Rails which also splits t
by ajmurmann 3y ago
Your last paragraph is really interesting to me. It obviously makes total sense. Yet, three environment I've used most in my career is Rails which also splits these things into folders by type rather than feature. It's never bothered me. Now I wonder if that because Ruby isn't Java and folders aren't packages or because I'm so very used to it.
- _ea1k 3y agoI've worked in a few codebases that tried to group things by feature. In my experience, it never really worked that well. Usually there would either be poor isolation between them or they'd be so well isolated that I'd wonder why they were even in the same project. In the latter, they'd often be difficult to maintain because of a web of dependencies pulled in by the little isolated subfeatures. I prefer the separation by type, tbh. It also has the upside that it naturally encourages the developer to follow the same patterns within that particular package.
- lcnPylGDnU4H9OF 3y agoI'm not sure what I prefer because I'm most familiar with Rails. I guess I'm used to type-separation. An individual Rails app could be structured using "engines"[0], which could easily allow for this kind of separation. Each engine will have its own app/ directory which contains models/, controllers/, services/, etc. The point is that the feature is its own "project" which would likely be loaded in the host application as a gem. I don't think this is actually a strong convention either way in Rails, so it would still be compatible with convention-over-configuration to build an app this way. (Kinda just thinking out loud. FWIW, I have worked on an application with a similar sort of "engine-primary" structure but not what I currently work on.) [0] https://guides.rubyonrails.org/engines.html https://guides.rubyonrails.org/engines.html
- arcbyte 3y agoThere's a certain amount of disciplined duplication that you have to adopt as well. I think this hangs a lot of people up and failure to do it right leads to the complications you're discussing. Adding a todo note, marking it done, editing it, and deleting it are all different use cases and each have thier own package and classes. However, most people want to have some kind of single ToDoNote class which is the "To Do Note". Doing that means they have to decide which package to put it in and then pull it in everywhere else. And then "common" logic starts piling up and features depend on crap from other features and accidental complexity starts creeping in. Now you've got a single ToDoNote class that has different sets of properties null or pipulated depending on where it was instantiated and what use case its being fed to, all requiring the programmer to keep this in their head instead of getting the compiler to help. The reality is that the set of data you need to create a todo note is different from the data you need to edit it which is different from that which you need to delete it. They share common elements, but never at the same time. The solution is to create "NewToDo", "EditedToDo", and "DeleteToDo" models that for each feature. Sure, some of the models will share a "title" property (new and edit), and some will share an "id" property (edit and delete) but never all at the same time. This offloads this complexity from the programmer to the compiler and speeds up development. You already know youre operating at the lowest of the low leves of excellence if you rely on monkey see monkey do code standards. Having low complexity code with minimal programmer brain space needed to operate in is how you level up to higher levels.