This is an issue of code management that I've run into several times. Say I've got a winforms application, and there is a lot of content - hundreds of controls worth of content, most of which have an attached event handler and method. When looking for recommendations on how to separate out such a large file, the 2 big ones that come to mind are regions & partial classes. However, these are both damned by almost every top answer out there.
So I'm wondering, what is the best practice for separating out something like this? It wouldn't make sense to separate them into new classes as they're simply control event handlers. Regions are nice but can still be extremely messy with so much code. I'm kind of at a loss, I can't figure out how to apply the SRP here and any recommendation I see seems to be considered bad practice.
The 'proper' way would be to split the form up into user controls.
Partial classes are meant to separate generated code from user code and regions are just layout (and useless in my opinion, but that is just an opinion)
Splitting the window in user controls promotes proper encapsulation and re-use.
Depending on the project, it might be too expensive to clean it up but splitting out couple of easy ones might help the readability and might save you some time when debugging. Also, when adding new controls and logic, consider adding user controls and start the process of splitting up that way. The cost will then be spread over a longer period and will only be paid for part that you actually use and need to be readable.
Related
I am developing a winform application where a set of classes and its methods calculate a geometry from 3d points.
As there is some input from the user needed from step to step in the algorithm we have designed some buttons which represent the steps. The intermediate data is stored in a class (maybe we use a structure in future Versions), so as the user input is. As result of pushing the Buttons the intermediate data will be calculated, saved and shown to the user, so that he can edit it, affecting to the calculation in the next steps.
The application began as an application which calculate everything in 4 steps but now we have more than 10 steps so we have divided it into 3 parts (horizontal geometry, vertical geometry and other...). Now I am doing some divisions because everything is getting too complex to manage all the gui interaction in one Form so I will create user controls for the smaller parts of the form.
Do you have general recommendations for me?
Should I have these data structures (input and intermediate data) in the controls I make or in the general form?
You should avoid mixing UI with the business logic. In that way when the program grows larger it will be a lot easier to maintain. It will also make it much simpler to write automated unittests.
If there is no particular reason you are using winforms. I would recommend using Windows Presentation Foundation (WPF). Read a tutorial about the Model View ViewModel (MVVM) design pattern. This is a very nice way of separating the UI logic from the business logic.
It takes some effort to switch from Winforms to WPF but it is definitely worth it.
EDIT (answer to comment)
Well it depends on the problem your solving. But generally:
In the MVVM pattern the:
Model would contain all your data and algorithms in classes/methods. The ViewModel would connect all the stuff you have in your Model and control the flow of the program, it will expose properties (commands, strings, numbers collections etc...) that view can bind to. The View is simply a "skin" that makes it possible for the user to communicate with the ViewModel. This is a very simple explanation of the MVVM pattern and I would recommend reading a tutorial about it.
The first time I came across this pattern it was called Model View Controller MVC, I like what AngularJS is doing by just calling it Model View Whatever MVW because there are a lot of MV* out there. But WPF is specifically built for MVVM.
The most important thing, if your creating a program that is going to be used and maintained for many years, is to keep the code as simple as possible. Instead of writing all the functionality into the Button_Click event handler (I have seen some programs that do this), try to write a class or method for every single task (use long descriptive names), this is also called Seperation of Concerns. In other words one method/class should not do more than one tasks. The nice thing is that you end up with a "program flow controller" (ViewModel/Whatever) that just passes data from one method to the next. And just by looking at the code you go: Aha I know exactly what is going on here! In the same way when you look at your algorithms (Model) they should do a single job and all variables should be have descriptive names. This makes it very easy for other developer to understand the code.
I also have very good experience with dividing my namespaces according to type. So every time you have more than one object of some sort (DataProviders, FileReaders, etc...) create a namespace/subnamespace for them and put them in there. So when your creating a new object/interface/enumeration... you always know where to put it. And you always know where to find again: Oh its a DataProvider so it must be located in ProjectName.Objects.DataProviders :)
So my recommendation is: have some fun and read about: MVVM and SoC
Probably state machine diagram will help you do devide actions in parts. It's a better practice, to create some of diagrams before codding.
I just had a conversation with my manager relating to checkin\out policies on a project I'm currently working on. Basically I tried to edit a file that was already checked out by another developer and I couldn't - I asked my manager why we couldn't edit the same class at the same time and he gave this reason for turning that functionality off: We had a lot of problems with developers editing the same Form (or anything visual done in the designer) and then cheking it in. Merging the changes in the designer generated code was a lot of hassle...
As I'm writing this I'm struggling to see what problem they were having - surely they were getting the latest code before trying to check something in??
Have any of you come across problems with editing the same Form (or something in the designer) as another developer and then checking into TFS? If so how did your team get around the problem? Did you also turn off the ability for developers to work on the same class?
EDIT: The following post (found here) is exactly the problem my manager was describing. Anyone know of a simpler way to resolve the issue than the ones in that post?
I would argue that the solution to your problem would be to establish best practices for source code modification.
Discourage people from going into UI code and arbitrarily jiggling the components around in the designer. Any reasonable UI modifications should be easily mergeable. Your best bet is to try and educate people as to the best way to merge in any given source control system. Also, as helpful as the designer is, ignorance of what code is being automatically generated in the background will be significantly detrimental in the long-term.
People who insist on locking checked-out files for the reasons you stated in your post typically wait long periods of time to check their code in. Naturally, the more time passes, the more code gets modified, so it makes merging difficult for these people. Checking in early, often, and incrementally requires people to think about their changes in stages, and for some coders, this is a rather painful cultural/psychological adjustment.
I've just checked back through the histories of some of my .designer.cs files and I can't see any changes that would cause a merge problems. There were no wholesale rearrangements of code for example.
Another thing to consider is to make sure that everyone does a "get latest" at regular intervals then any individual merge/resolution isn't going to be that great thus minimising the chances of anything going wrong.
It might also be worth investigating a 3rd party merge tool. There are plenty around.
Now it could be that the changes I've done are simple compared to the ones you've got so you should take my anecdotal data with a pinch of salt.
It can cause problems (in general) when a lot of people are editing UI concurrently. The merge logic will do a fine job merging things, but in a lot of cases the UI is drawn according to how things are added to the form. Your UI can get messed up quickly.
I don't know if I would use this as an excuse to enforce exclusive checkouts across the board, though. I might go from a (non programmatic) policy standpoint that says shared checkout for business logic, but exclusive for UI changes.
I would couple that with a strong MVP, MVC, or MVVM approach, though, which should limit the number of people that have to touch the UI concurrently.
As others have alluded to, keep one of the seminal rules of SCM in mind: merge early and often, and your problems are reduced. (along with that is "always get latest before you start working on the code).
I'm refactoring some code I wrote a few months ago and now I find myself creating a lot of smallish classes (few properties, 2-4 methods, 1-2 events).
Is this how it's supposed to be? Or is this also a bit of a code smell?
I mean if a class does need a lot of methods to carry out it's responsibility, I guess that's how it's gotta be, but I'm not so sure that a lot small classes is particularly good practice either?
Lots of small classes sounds just fine :)
Particularly if you let each class implement an interface and have the different collaborators communicate through those interfaces instead of directly with each other, you should be able to achieve a so-called Supple Design (a term from Domain-Driven Design) with lots of loose coupling.
If you can boil it down so that important operations have the same type of output as input, you will achieve what Evans call Closure of Operations, which I've found to be a particularly strong design technique.
What tend to happen when you apply the SRP is that although all classes start out small, you constantly refactor, and from time to time it happens that a rush of insight clarifies that a few particular classes could be a lot richer than previously assumed.
Do it, but keep refactoring forever :)
Lots of small classes with focused responsibilties are what srp is all about. So, yes, this is the way things are "supposed to be" as far as srp advocates are concerned. But you're seeing an explosion of the number of classes in your system and it's beginning to become very difficult to remember or to intuitively know where things are actually done, isn't it? You are, indeed, exposing a new code smell, which is the (usually unnecessary) increase of complexity that comes aong with srp. I wrote an entry about it here. See if you might agree.
I think you have to find the middle way. Too many classes are sometimes overkill. From my side I try to separate concerns on a smaller level and if things are getting then refactor out more coarse grained:
First write separate concerns by extracting methods. If you can see a group of methods on data (instance + static fields) to form a dedicated responsibility 'extract class'. After a while if you can see different groupings of classes inside a package do 'extract packages'.
I found this (explosion) approach more natural as creating lots of classes and packages from start on. But this also depends...: If I can already see bigger components at the beginning I already create dedicated package structures.
Maybe some more details about your code to offer some more concrete help :)
What are bloating controls?
Can anyone please explain it?
It's a term which can be used to describe a variety of things, e.g. it is commonly used by critics of ASP.NET WebForms where, if you are making heavy use of pre-built WebControls you have little control of the generated HTML, which in many cases appears 'bloated' (large) and 'unclean', 'messy', etc.
I'm not sure 'bloating' is exactly what you mean. Some controls could be called 'bloated'.
In that case it means that some controls offer a great deal of functionality which in most cases is not required. Grid controls tend to be fairly bloated because they expose functionality for sorting, filtering, binding, templating etc.. but it's unlikely that you'll use all of this in a single implementation of the grid so you're taking up much more memory than you actually need which could potentially cause performance issues.
Hope this helps.
I guess people are referring to the fact that some GUI controls are very big and thus a bit hard to understand / use.
Are there limits or performance penalties on the amount of code inside of my home.cs form?
I am writing a database application front-end in C# in Visual Studio 2008. The way things are lining up, I am using a tab-page way of changing the info shown to the end users, instead of using new forms.
Coming from VBA/MS Access, I remember that if you go over a certain number of lines of code, it would produce an error and not compile. Will C# do this in Visual Studio 2008, or will I suffer a performance hit? I know code readability could be a problem because everything would be in one place, but I can also see that as an advantage in some situations.
It's not the lines of code in your .cs files that you need to be worried about with regards to performance - it's the number of controls on your form at runtime that might cause problems. If it's just a few controls on a few tabs, you will have no problems. If it's hundreds of controls on lots of tabs, you may have performance problems (not to mention usability problems - I personally hate tab controls with more than one row of tabs).
Also, I don't think tabs are appropriate if the purpose of the UI is more wizard-like where you want the user to interact with all of the tabs in succession. Tabs are meant for presenting sets of options to the user, without requiring them to see all the options at once.
Finally, if the purpose of each tab is significantly different, I find that it's easier to encapsulate each bit of functionality as a separate form. With tabs, you could at least encapsulate each bit as usercontrols, and then have each tab on your form host one instance of a usercontrol.
The only problem i would foresee is that in the future its going to be very hard to maintain.
Try break the logic of that main form up as much as possible into classes so that when you need add something you can actually do it without having a fit.
If you are using tabs, you can still create custom user controls that will hold the content that goes in the tabs. Make a control per tab, and then you can keep your code for the different tabs separate. There is a walk-through on MSDN here.
In response to your comment above, about not showing the tabs, I would really re-think how you're approaching this. Why not simply have all of your user controls sitting on your main form, in a Panel if necessary, have them all set to Dock = DockStyle.Fill, and then change the Visible and Enabled properties based on which one you want to show? You may be making this harder on yourself than it needs to be.
More responses to comments - You may be looking for something like the CardLayout in Java. The source for the GNU Classpath version can be found here, it might give you some ideas on how to implement this.
"I know code readability could be a problem because everything would be in one place, but I can also see that as an advantage in some situations."
In my experience, this attitude will ultimately leave anyone who has to maintain your code in the future with quite a headache, as it's an accepted practice to modularize your code so that the pieces that may change or the ones that serve distinctly different purposes are separated away from each other.
With that said, I don't think there is a limit imposed by VS on the length of your files, but I think you will run into some seriously frustrating performance degradation as your files become longer, especially while switching between design and code views.
I would urge you to save your future self and his/her sanity and break your code up logically into separate files. You'll thank yourself later!
It shouldn't be a problem.
Just keep good coding practices in mind and modularise your code for readability and maintainability.
On the other hand, if you put too many controls on your form, then it will probably take longer to load. Factor that into your design if you want a snappy interface.
Sounds horrible but I don't see any reason why it would be a problem.
I have a form that in inherited with my new job that had over 30,000 Lines. It is completely cancerous. Please think before you code and modularize!