views:

224

answers:

10

What do you think of this kind of code-to-files-mapping?

~/proj/MyClass.ext  
~/proj/MyClass:constructors.ext  
~/proj/MyClass:properties.ext  
~/proj/MyClass:method-one.ext  
~/proj/MyClass:method-two:int.ext
~/proj/MyClass:method-two:string.ext

In a language which is more functional-oriented:

~/proj/definitions.ext  
~/proj/function-one.ext  
~/proj/function-two:int.ext  
~/proj/function-two:string.ext  
...

The point would be that when we are working on our project, we don't see this multiplicity of files.

We might either have some kind of daemon process that keeps a mirror MyClass.ext file perfectly in sync with this bunch of files, or our favorite code editor sees them all but shows them as their logical aggregation, or this kind of conversion only happens as a set of pre+post-commit hooks.

Now, since we wouldn't be interested in this idea's implementation if it's not a good idea, let's not bother ourselves with its implementation details (the how); let's suppose we've got the perfect implementation that would make this idea to work well for us.

What I would like for us to find together is a good list of pros & cons to this approach, both at a high level and at more specific low levels of your concern.

When we'll be done brainstorming this and seeing each answer's votes, we should see easily if this is a good idea or not. Therefore, please write one pro/con per answer.

EDIT

From all the answers and especially Scott's, I derived that the only real way my idea might be useful, would be to be able to bring automatic listing of changed class:method couples in the detailed part of each commit-to-vcs message. This could much more easily be achieved by small scripts run before commits, to update the message template accordingly.

A: 

Personally I would find that that type of separation, although possible in some languages, would be a nightmare to maintain, and would make following the code really hard. I personally find that with .NET languages regions in code are far more helpful.

I would be concerned on large projects with the sheer number of files.

Mitchel Sellers
As stated in the question, we assume> we've got the perfect implementation that would make this idea to *work well* for us.This means that when we work in our code editor, there's strictly no difference for us. If you meant something else, please clarify.
Daniel Jomphe
A: 

Pro Commit changesets should carry much more information about what really happened for this commit to come to life without having to show a diff:

  • Many files listed for the same class suggest it's been refactored;
  • On the opposite, only one file change listed for a class would suggest its behavior has only been slightly modified.
Daniel Jomphe
A: 

Con On a performance stand-point, all these file I/Os could cost much in big working trees.

Daniel Jomphe
+4  A: 

Perhaps the better question to ask in response is: What is the problem you would hope to solve with this approach?

The .NET languages support some level of this idea with partial classes, although I've never seen it carried to that extreme and the editing experience is not as seamless as you describe in your "perfect implementation".

I can't really see the usefulness of such a scenario. Yes, having multiple files means less potential risk of a change affecting other parts of the code but I don't think that outweighs the performance impact of parsing the files to show it as one editable file.

Scott Dorman
My Pro answer is what I hoped to solve with this approach.
Daniel Jomphe
In that case, your changesets should include better checkin comments. These can be used for any number of secondary purposes, including a running list of changes for each build. The comments need to be more than just "changed xxx line of code" as a diff can tell you that much.
Scott Dorman
Thinking of it, my Pro answer isn't a full answer to your question. The real point of my idea would bring automatic listing of changes per class+method. This could much more easily be achieved by small scripts run before commits, to update the message template. Thanks for your question, Scott!
Daniel Jomphe
You're welcome. I think using the ability of a source control system to run scripts before/after commits to do this type of analysis is a good way to do it.
Scott Dorman
+1  A: 

I think like everything it has to be a balance - and it seems like Frameworks are often on either side of the spectrum.

aka Camping vs. Rails et al.

The level of granularity you mapped out above seems a little over the top to me. I foresee refactoring being a nightmare. Even in frameworks like ASP.net and Ruby on Rails, I find myself constantly cleaning up my workspace because I have too many files open and its causing productivity issues.

  • con: lots of open files when developing
  • con: refactoring would be complicated and disorienting
  • con: more prone to files breaking naming conventions and interference with actual syntax errors
  • con: for interpreted languages, test harnesses would have to include many more files - there would have to be some smart inclusion methods to get everything that was needed to interpret a class.
  • con: the filestystem is less representative of an object orientation - sometimes it's nice being able to easily ascertain the classes in a given folder.

Sorry - I want to offer a pro here but it's just not coming to me

danpickett
On one hand, I'd say that my last implementation example already eliminates your cons #1, 2, 4, 5, as it makes the working copy exactly like we're used to see it (I understand you say it's important for it to remain this way). On the other hand, I understand it might be hard to impl. it perfectly.
Daniel Jomphe
+1  A: 

Hard disk space.

On a default windows installation every file takes up at least 4k. Other file systems can take more or less but there's almost always a minimum size. I could see a large software project all of the sudden taking up a large amount of disk space with this system. This might not be a huge problem on the developer's machines but I'd be concerned about the source control server since it seems like servers never have enough disk space.

Bryan Anderson
+1  A: 

I agree, this is way too granular.

However, I have considered separating members by scope:

ClassA-interface.cs      (public members)
ClassA-implementation.cs (non-public members)

Of course, you could go further, but even this bifurcation doesn't "solve a problem" that I have. While it would make me more conscious of changes likely to affect client code, I'm better off learning that through tests.

harpo
+2  A: 

CON

Class-per-file lets you wrap your brain around the class as a whole. If your classes are large to the point of being many multi-page monstrosities, you might need to split the methods to separate files, but you might as well refactor and save yourself some maintenance headache. This is one of the arguments against #region as well.

Jimmy
+1  A: 

PRO:

I've noticed that many GNU C libraries split up their source into 1 function per translation-unit files. From what I gather this is to assist when statically linking the library into a binary. Apparently, when searching for a symbol, the linker will include the entire translation unit in which the symbol resides (which makes sense, since there might be static functions and data in the unit which the symbol depends on). Therefore if you split your code into granular files, its possible that you could keep your static-linked file sizes to a minimum.

I would imagine that in C++ there are fewer benefits, especially for classes with virtual members, as the virtual table would introduce multiple symbol dependencies.


CON:

Unless you had built-in IDE support for this mapping it seems that maintainence of anything at the granularity level of methods would be problematic as people make wholesale changes to classes. In projects I work on, functions get will get occasionally renamed in order to more accurately reflect their changing behavior. Adding a file rename on top of the function rename is just one more step for people to screw up.

pk
+1  A: 

Some version control systems, notably Git (and probably BitKeeper), work on this level by design, instead of on a file level.

Pro: Especially when refactoring (on branches), this might come in very handy (being able to specify that a single method has moved from one class to another, or that a part of a class has been moved). A system that works on a lower level of granularity than files could resolve merge conflicts easier (because it can track where a method has moved, and can apply the changes accordingly to multiple files).


Con: I think you really need a VCS that supports it by design, instead of trying to duct-tape it on a file based VCS (Git doesn't work too well on Windows, and BitKeeper is commercial software). Another drawback is that you probably can't do it in a language-agnostic way. AFAIK, Git employs some advanced heuristics to track the individual pieces of content in a file, but it's not infallible, and there might be some languages with nonstandard (not C-like) function/method syntax where conventional heuristics might fail (Prolog predicates).

Kim Sullivan