Hacker News new | comments | show | ask | jobs | submit login
I have a question about organizing projects (github.com)
24 points by raganwald 3119 days ago | hide | past | web | 18 comments | favorite

In Monkeybars we decided to group all parts of the MVC tuple under the same directory because we mainly work with them as a set. It's too annoying to have to bounce around from a model dir to a controller dir to a view dir.

MVC|MVC|MVC is more natural grouping than MMM|VVV|CCC.

I ask myself "What does the each patten make easy? What does each pattern make difficult?" The standard or "verb-oriented" organization makes it easy to manage cross-cutting concerns, like rewriting all of your views in HAML instead of in erb, or adding a "created_at column to every model table. The refactored, or "noun-oriented" organization makes it easy to manage model concerns, like adding a new controller action with its associated views, model changes, tests, and migrations.

I find the latter happens far more often than the former for me, so it feels like a win even if I have no interest in sharing a model between applications.

Perhaps both schemes could be supported, using a system of symbolic links, or in its most elite case maybe even a specialized user-space filesystem. Now you have me thinking...

That's a classic matrix problem. Information fits nicely in two categories. How do you organize it? Choosing one or the other is mostly arbitrary. But current file systems force you to make a choice. BeOS a long time ago sort of wanted to fix that...

I actually do organize my plugins as raganwald suggests...and, as we've rolled out more products, and I'm seeing increasing commonality in pieces between then, am thinking more and more than 90+% of every one of our projects should be all plugin code.

Raganwald is also mentioning refactoring the code so that the data objects become responsible for persisting and displaying themselves though.

I don't necessarily have any problems with the persisting (that's how ActiveRecord works out of the box), but I'm not sure about the displaying, because I sometimes want to display things differently depending on the context.

Well, I gave a very trivial example showing that, but I don't necessarily believe it should always work that way. Let me be more specific: If you have a Persistanceamajig that know the difference between an account and a customer, then you might want to break it up. On the other hand, if the Persistancamajig can do its job by inspecting the things you pass to it, then it may be a very good idea to keep its implementation separate.

Likewise if you want a separate Displaythingie that can work out how to display an account or a customer on its own, great. If it needs to know a lot about accounst and custoemrs to do its job, but you want to swap it out or paramaterize it (e.g. one set of views for iPhone, one set for Safari), the classic organization makes a certain amount of sense.

All that being said, I have built a large, public-facing app with multiple views for multiple devices, and my experience is still that we did modifications across all of the things related to a model much more often than doing modifications to all of the views across all of the application.


Actually, I would say that the very first example is the correct organisation with proper separation of concerns. The reason they are often merged into the form of the second code sample is for convenience rather than for organisation. From a code design perspective, this is not a good thing (and I know many people who complain that Rails made a mistake with that). From a testing perspective, for instance, the coupling between the User object, the methods that save and load that object from the db, and the validation code, make it much harder to write cleanly isolated tests.

There are plenty of architectures where "data objects" are dumb and are passed to more intelligent objects that can save them, serialize them, etc.

MMM|VVV|CCC is a better system than MVC|MVC|MVC because it encourages separation of concerns, and loose coupling between concerns. Tight coupling between mostly unrelated pieces of functionality (why should the persistence code know anything about the controller?) is a very nasty code smell.

> why should the persistence code know anything about the controller?

They don't know anything about each other. The question is not whether M,V, and C should be the same entity. The question is why they are scattered all over an application, such that adding a single field to a model involves going to one place to add a migration, another place to add validations and other model logic, a third place to change controller logic, a fourth place to change one or more views, and so forth.

Should they be separate files? Perhaps yes. Should they be far away from each other? That is what I am questioning. The "Separation of Concerns" you are describing is not a very persuasive argument in Rails apps, IMO, because I often have a concern like "add a field to this model" and I rarely have a concern like "Change from HTML 4.0 to XHTML" or "Add a created_at column to all tables."

In "separation of concerns" I'm talking about functionality, not human concerns. See: http://en.wikipedia.org/wiki/Separation_of_concerns

Separation of concerns aims to produce modular, loosely coupled code.

Now, if we start from the point of view that they should be in separate files anyway (in the ruby way, each file should contain one class rather than many - and I don't think it's helpful to change that), then I don't see what difference it makes whether the files are in the same directory or in separate directories.

If you have any sort of decent editor, opening the file you seek should be a matter of pressing a shortcut and typing part of the filename... Certainly, I rarely use the mouse to open files - except when i'm browsing through a new project, but that's a fairly rare use case.

Now, there's another problem I can see with your proposed organisation: although in some cases (even many) applications are built around resource objects, almost every non-trivial application has many edge cases of functionalities that are not directly attached to objects, or are attached to multiple kinds of objects, or are attached to objects but in a way that could be mapped to one object or to another, and is actually best thought of as being linked to something else.

Forcing the file system to be organised around resources like users, projects, items, etc would coerce us into trying to fit functions onto specific objects - and, importantly, it would remove the flexibility of being able to not tie a function to an object.

As such, I think the current model is more flexible and offers something that your proposed model doesn't support and which is useful on most projects.

Django useses this Approach: app/ ---- models.py ---- views.py ---- urls.py ---- admin.py etc.

etc. I think it does indeed make more sense. Though the difference is not that big except for one case: Reusability of the code, that way you can easily just copy the directory to another site.

Almost. I wouldn't keep the extra cruft of vendor, plugin, app and controllers for the simpler divisions of object (say those that are just 1 model, controller, and views), but I've often wondered about that in Rails.

I would not give the refactoring recommendation you suggest. I would make both Account and Customer 'Displayable' and 'Persistable' ( still thinking in Java :( ). Then implement a kind of Strategy pattern to take a Displayable object. Same goes for Persistable.

That way you can focus on the domain objects as data, and how they are related to each other. You can also come up with cleaner (and more orthogonal) patterns of how to display, persist, or otherwise handle that data.

Interesting, reminds me of the HMVC pattern (Hiearchical MVC) or the Presentation abstraction control

PAC : http://en.wikipedia.org/wiki/Presentation-abstraction-contro... HMVC : http://www.javaworld.com/javaworld/jw-07-2000/jw-0721-hmvc.h...

Switch to an image-based system like Smalltalk or hybrid image/file-based system like Common Lisp. Seriously, a lot of the headaches of organization would go away if dev environments were more like Smalltalk.

Visitor Pattern. To me it really depends on the context and how many "majigs" you're going to have, how flexible your application needs to be -- do you need to leave layers open to other implementations (different view, different transport, different persistence strategy)? I've gone both ways in the past with different projects, but if I were identify a rule for myself it would be that frameworks go the first way (easier to extend or swap components) while plugins go the second way (self-contained functionality).

If you can handle a larger number of classes you can sort of get around the question by using a good plugin loader that can associate the proper Persistamajig or Displayamajig with a particular object at run time.

Oh, and for double-extra bonus points add in the fact that you might have more than one presenter for a single model -- content type negotiation, don'tchaknow.

I can make no conclusive judgement in the example scenario until we're talking about specific algorithms and data.

Applications are open for YC Winter 2018

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact