views:

792

answers:

14

The project I'm working on has just hit 4200 lines in the main C# file, which is causing Intellisense to take a few seconds (sometimes up to 6 or so) to respond, during which Visual Studio locks up. I'm wondering how everyone else splits their files and whether there's a consensus.

I tried to look for some guides and found Google's C++ guide but I couldn't see anything about semantics such as function sizes and file sizes, maybe it's there - I haven't looked at it for a while.

So how do you split your files? Do you group your methods by the functions they serve? By types (event handlers, private/public)? And at what size limit do you split functions?

Edit: To clarify, the application in question handles data - so it's interface is a big-ass grid, and everything revolves around the grid. It has a few dialogs forms for management but it's all about the data. The reason why it's so big as there is a lot of error checking, event handling, and also the grid set up as master-detail with 3 more grid for each row (but these load on master row expanded). I hope this helps to clarify what I'm on about.

A: 

Use Partial classes. You can basically break a single class into multiple files.

Chris Lively
That sounds like treating the symptoms rather than the possible design problems.
Jon Skeet
I agree with Jon.
Tim
I didn't think it deserved a down vote though. It does make the files smaller...
Tim
No it didn't deserve a down vote even though the answer was as clueless as the question.
Owen
OP here. Sorry about being clueless but that's why I came here :) I have done one class file as partial but why is this not the right way? Should I be subclassing?
alphabeat
@alphabeat: No, you probably shouldn't be subclassing - you should be dividing the functionality up into smaller types.
Jon Skeet
I'd suggest that splitting a large class up into partial classes is about as appropriate as using #Regions to "split" up a large function.: Hiding the problem rather than fixing it.
Richard Ev
@alphabeat sorry for the clueless remark, I meant no offence. Its hard to say what you should be doing without seeing your code. You should subclass when its logical to do so i.e. several super classes that would seem require to derive from a common base class.
Owen
@Owen No worries! I'd love to share my code but my boss would murder me twice :) Thanks for your suggestion.
alphabeat
+8  A: 

Split your types where it's natural to split them - but watch out for types that are doing too much. At about 500 lines (of Java or C#) I get concerned. At about 1000 lines I start looking hard at whether the type should be split up... but sometimes it just can't/shouldn't be.

As for methods: I don't like it when I can't see the whole method on the screen at a time. Obviously that depends on size of monitor etc, but it's a reasonable rule of thumb. I prefer them to be shorter though. Again, there are exceptions - some logic is really hard to disentangle, particularly if there are lots of local variables which don't naturally want to be encapsulated together.

Sometimes it makes sense for a single type to have a lot of methods - such as System.Linq.Enumerable but partial classes can help in such cases, if you can break the type up into logical groups (in the case of Enumerable, grouping by aggregation / set operations / filtering etc would seem natural). Such cases are rare in my experience though.

Jon Skeet
+17  A: 

I think your problem is summed up with the term you use: "Main C# file".

Unless you mean main (as in the method main()) there is no place for that concept.

If you have a catch-all utility class or other common methods you should break them into similar functional parts.

Typically my files are just one-to-one mappings of classes.

Sometimes classes that are very related are in the same file.

If your file is too large it is an indication your class is too big and too general.

I try to keep my methods to half a screen or less. (When it is code I write from scratch it is usually 12 lines or fewer, but lately I have been working in existing code from other developers and having to refactor 100 line functions...)

Sometimes it is a screen, but that is getting very large.

EDIT:

To address your size limit question about functions - for me it is less about size (though that is a good indicator of a problem) and more about doing only one thing and keeping each one SIMPLE.

Tim
The Main C# file comment got me too. Does it do exactly 1 small job/manage 1 concept? If not, find a part that does exactly 1 small job, refactor it into a class of it's own, wash, rinse and repeat.
Bill K
+4  A: 

Don't code procedurally and you won't end up with 4200 lines in one file.

In C# it's a good idea to adhere to some SOLID object oriented design principles. Every class should have one and only one reason to change. The main method should simply launch the starting point for the application (and configure your dependency injection container, if you're using something like StructureMap).

I generally don't have files with more than 200 lines of code, and I prefer them if they're under 100.

Chris Holmes
Wow, 4200 seems very bloated, which I guessed, but this just makes me embarrassed. If it helps, it was err, like this when I got here :)
alphabeat
Note: It doesn't count as OO programming if you have just the one large object!
Richard Ev
*cries* at work we have an app with at least 20+ objects in the business library that have more than 10-30k lines in a .cpp... and they ARE all in at least 6 files.. ;_;
uzbones
@Richard E: It has plenty more objects, but this one has just become bloated over time (see my edit).
alphabeat
+1  A: 

Well I'm afraid to say that you may have a bigger issue at hand than a slow load time. Your going to hit issues of tight coupled code and maintainability/readability problems.

There are very good reasons to split class files into smaller files (and equally good reasons to move files to different projects/assemblies).

Think about what the purpose that your class is supposed to achieve, each file should really only have a single purpose. If its too generalized in its goal i.e. "Contain Shopping Basket Logic" then your headed down the wrong path. Also, as mentioned the term you use: "Main C# file" just reeks that you have a very procedural mindset. My advise would be to stop step back and have a quick read up on some of the following topics:

  • General OOP principles
  • Domain driven design
  • Unit testing
  • IoC Containers

Good luck with your searches.

Owen
+4  A: 

Martin Fowler's book Refactoring I think gives you a good starting point for this. It instructs on how to identify "code smells" and how to refactor your code to fix these "smells." The natural result (although it's not the primary goal) is that you end up with smaller more maintainable classes.

EDIT

In light of your edit, I have always insisted that good coding practice for back-end code is the same in the presentation tier. Some very useful patterns to consider for UI refactorings are Command, Strategy, Specification, and State.

In brief, your view should only have code in it to handle events and assign values. All logic should be separated into another class. Once you do this, you'll find that it becomes more obvious where you can refactor. Grids make this a little more difficult because they make it too easy to split your presentation state between the presentation logic and the view, but with some work, you can put in indirection to minimize the pain caused by this.

Michael Meadows
+1  A: 

There are no hard and fast rules, but there's a general agreement that more, shorter functions are better than a single big function, and more smaller classes are better than 1 big class.

Functions bigger than 40 lines or so should make you consider how you can break it up. Especially look at nested loops, which are confusing and often easy to translate to function calls with nice descriptive names.

I break up classes when I feel like they do more than 1 thing, like mix presentation and logic. A big class is less of a problem than a big method, as long as the class does 1 thing.

The consensus in style guides I've seen is to group methods by access, with constructors and public methods on the top. Anything consistent is great.

You should read up on C# style and refactoring to really understand the issues you're addressing.

Refactoring is an excellent book that has tips for rewriting code so that behavior is preserved but the code is more clear and easier to work with.

Elements of C# Style is a good dead tree C# style guide, and this blog post has a number of links to good online style guides.

Finally, consider using FxCop and StyleCop. These won't help with the questions you asked, but can detect other stylistic issues with your code. Since you've dipped your toe in the water you might as well jump in.

That's a lot, but developing taste, style and clarity is a major difference between good developers and bad ones.

RossFabricant
A: 

A simple method to use is if you have regions of code within a class use the partial key word and breakout that definition of the class into that file. I typically do this for large classes.

The convention I use is to have the ClassName_RegionName.cs. For example if I want to break out a class that manages the schema for a database connection and I called the class DatabaseConnection I would create a file called DatabaseConnection.cs for the main class and then DatabaseConnection_Schema.cs for the schema functionality.

Some classes just have to be large that's not bad design they are just implementation heavy.

Jeremy Edwards
+1  A: 

Each class should do one small thing and do it well. Is your class a Form? Then it should not have ANY business logic in it.

Does it represent a single concept, like a user or a state? Then it shouldn't have any drawing, load/save, etc...

Every programmer goes through stages and levels. You're recognizing a problem with your current level and you are ready to approach the next.

From what you said, it sounds like your current level is "Solving a problem", most likely using procedural code, and you need to start to look more at new ways to approach it.

I recommend looking into how to really do OO design. There are many theories that you've probably heard that don't make sense. The reason they don't is that they don't apply to the way you are currently programming.

Lemme find a good post... Look through these to start:

how-do-i-break-my-procedural-coding-habits

are-there-any-rules-for-oop

object-oriented-best-practices-inheritance-v-composition-v-interfaces

There are also posts that will refer you to good OO design books. A "Refactoring" book is probably one of the very best places you could start.

You're at a good point right now, but you wouldn't believe how far you have to go. I hope you're excited about it because some of this stuff in your near future is some of the best programming "Learning Experiences" you'll ever have.

Good luck.

Bill K
+1  A: 

You can look for small things to change and change each slowly over time.

  • Are all the methods used in that class only? Look for support methods, such as validation, string manipulation, that can be moved out into helper/util classes.

  • Are you using any #region sections? Logical groupings of related methods in a #region often lend themselves to being split into separate classes.

  • Is the class a form? Consider using User Controls for form controls or groups of form controls.

Sometimes large classes evolve over time due to lots of developers doing quick fixes / new features without considering the overall design. Revisit some of the design theory links others have provided here and consider on-going support to enforce these such as code reviews and team workshops to review design.

Leah
A: 

Perhaps the OP can respond: is your project using Object-Oriented Programming? The fact that you use the word "file" suggests that it is not.

Until you understand object orientation, there is no hope for improving your code in any important way. You'd do better to not split up the file at all, wait until it grows to be unbearably slow and buggy, then instead of bearing it any more, go learn OO.

John Saunders
A: 

The Intellisense parser in Visual Studio 2008 seems to be considerably faster than the one 2005 (I know they specifically did a lot of work in this area), so although you should definitely look into splitting the file up at some point as others have mentioned, Visual Studio 2008 may resolve your immediate performance problem. I've used it to open a 100K+ line Linq to SQL file without much issue.

tbreffni
Should have clarified sorry but I am using VS2008. Problem is it's such a large project and the code for the main form is so giant. It's become sort of a dumping ground I guess.
alphabeat
+12  A: 

In the classic book "Structured Programming" Dijkstra once wrote a section entitled: "On our inability to do much." His point was simple. Humans aren't very smart. We can't juggle more than a few concepts in our minds at one time.

It is very important to keep your classes and methods small. When a method gets above a dozen lines or so, it should be broken apart. When a class gets above a couple of hundred lines, it should be broken apart. This is the only way to keep code well organized and manageable. I've been programming for nearly 40 years, and with every year that has gone by, I realize just how important the word "small" is when writing software.

As to how you do this, this is a very large topic that has been written about many different times. It's all about dependency management, information hiding, and object-oriented design in general. Here is a reading list.

Uncle Bob
A: 

Split the code so that each class/file/function/etc. does only One Thing™. The Single Responsibility Principle is a good guideline for splitting functionality into classes.

Nowadays, the largest classes that I write are about 200 lines long, and the methods are mostly 1-10 lines long.

Esko Luontola