views:

284

answers:

5

I just finished creating my first major application in C#/Silverlight. In the end the total line count came out to over 12,000 lines of code. Considering this was a rewrite of a php/javascript application I created 2 years that was over 28,000 lines I am actually quite proud of my accomplishment.

After reading many questions and answers here on stackoverflow and other sites online, I followed many posters advice: I created classes, procedures, and such for things that I would have a year ago copied and pasted; I created logic charts to figure out complex functions; making sure there are no crazy hidden characters (used tabs instead of spaces); and a few others things; place comments where necessary (I have lots of comments).

My application consists of 4 tiles laid out horizontally that have user controls loaded into each slice. You can have between one and four slices loaded at anytime. If you have once slice loaded, the slice takes up the entire artboard...if you have 2 loaded, each take up half, 3 a third, 4 a quarter.

Each one of these slices represent (for the sake of this example) a light control. Each slice has 3 slider controls in it. Now when I coded the functionality of the sliders, I used a switch/case statement inside of a public function that would run the command on the specified slice/slider. This made for some duplicate code but I saw no way around it as each slice was named differently. So I would do slice1.my.commands(); slice2.my.commands(); etc.

My question to you is how do I clean up my code even futher? (Sadly I cannot post any of my code). Is there any way to take this repetion out of my code?

A: 

Since you can't really post any of your code, I might as well throw out a random thought. Can you put these slices into an array? If so you might be able to get rid of some of the redundant code by having each of the controls set a variable (I'll call it whichSlice). so the controls all set whichSlice to the proper number 1-4 and then you run a normal switch and call slices[whichSlice].my.commands();

Chibu
I dont think I can. I am loading another usercontrol for each slice. slice1.xaml, slice2.xaml, slice3.xaml. If your method can be done that would be great!
Mitchell Skurnik
+6  A: 

Writing less code shouldn't be your goal. In the end it's all about TCO (Total cost of ownership).

While owning less code can improve the TCO, there is one factor that has a much greater impact for TCO: maintainability. You should write the most maintainable code. Start by reading Robert Martin's Clean Code.

Update:

Also you say “I have lots of comments”. This is a point where you might improve your code. As you will learn from Martin’s book, good code hardly needs any comments. Martin says that “comments are lies” and “should be reserved for technical notes about the code and design.”.

Update 2:

While I'm add it, here are my favorite quotes from Robert Martin's book:

  • "a class or module should have one, and only one, reason to change [Single Responsibility Principle]" [page 138]
  • "More than three [method arguments] is very questionable and should be avoided with prejudice." [page 288]
  • "The First rule of functions is that they should be small. The second rule of functions is that they should be smaller than that." [page 34]
  • "Functions should hardly ever be 20 lines long" [page 34]
  • "The statements in a function should all be written at the same level of abstraction" [page 304]
  • "Comments should be reserved for technical notes about the code and design." [page 286]
Steven
This is one of those projects where I will finish it and then not touch it for 6-12 months. I just want to be able to come back in 6-12 months and understand what I did. I like what you and Robert Martin has to say about TCO.
Mitchell Skurnik
Robert Martin doesn't use the term TCO in his book, but this is what maintainability of course is all about. Maintainability is of course more than just readable code. For instance, when your code swallows exceptions without logging them; by! by! maintainability.
Steven
I added a note about comments in my answer.
Steven
+10  A: 

What you need is an interface with your friend the Strategy pattern. For example:

public interface ISlice 
{
    public Slider Slide {get;set;}
}

public class Slice1 : ISlice 
{
    public Slider Slide { get; set; }
}

public static class SliceSlider
{
    public static void DoSomethingCoolWithTheSliceSlide(ISlice slice) 
    {
        slice.Slide.LookitMeIAmLearningDesignPatterns();
    }
} 
roufamatic
This gets my vote. It sounds like the 'slices' are application-wide and an interface would be the best way to maintain the code. Steven had a good point too, getting the total line count shouldn't be your objective; clean, maintainable and SCALABLE code should be.Good luck!
Chris Laythorpe
Do you have any great tutorials/references on "interface". This sounds interesting.
Mitchell Skurnik
Off the top of my head, nothing that you couldn't google yourself. But if you really want to understand this stuff -- and it sounds like you're ready -- go buy "Head First Design Patterns": http://oreilly.com/catalog/9780596007126 . (ps how do I use markdown in comments?)
roufamatic
Head First Design Patterns is a great book for learning about design patterns. However, first read Clean Code ;-) And after Head First, read The Art Of Unit Testing (Roy Osherove). You got yourself some homework :-p
Steven
Instead of single method interfaces, use Delegates/Func.
Dykam
+2  A: 

I tend to agree with Steven. Writing less code, or fewer lines, is not always the goal. Thinking back to some of the stories of Steve Wozniak he used to make very compact hardware, putting tons of logic into a very small package, but very few people could follow what he did, maintain it, or manufacture it.

That being said, I suggest you get very familiar with Design Patterns. They may not lessen your lines of code but they may make you code easier to write, maintain, and understand. And a lot of times they do reduce the number of lines you have. Here are some resources:

DoFactory Design Patterns Reference

Wikipedia Design Pattern Acticle

Tim C
+2  A: 

Interfaces and abstract classes are a very strong part of the .net platform.

An interface is nothing more than a contract requirement on a class. That is: an interface is a defined set of methods and/or properties that a class implementing that interface must have. An interface is just a contract declaration.

An abstract class is really powerful because you can carry logic 'into' classes that implement that abstract class. But that is a whole other ball game.

Consider:

public interface ISlice
{
    bool DoStuff(string someParameter);
}

public class MySpecificSliceOfType : ISlice
{
    // this must have a method implementation for the [bool DoStuff(string)] method
    public bool DoStuff(string mySpecificParameter)
    {
       // LOGIC in the Specific class
       return(true);
    }
}

public class MyOtherSliceOfType : ISlice
{
    // this must have a method implementation for the [bool DoStuff(string)] method
    public bool DoStuff(string myOtherParameter)
    {
       // LOGIC in the Other class
       return(true);
    }
}

Whilst this is a heavily oversimplified example, declaring the Interface implentation of the ISlice interface on both the classes 'MySpecificSliceOfType' and 'MyOtherSliceOfType' means that the requisite DoStuff() method is regardless of which one you have because you can do things like:

bool sliceReturn = ((ISlice)currentSlice).DoStuff(currentStringParameterValue);

This can save you working through in things like:

bool sliceReturn = false;
switch(typeofSlice)
{
    case "other" :
        sliceReturn = MyOtherSliceOfType.DoStuff(currentStrignParamterValue);
        break;
    case "specific" :
        sliceReturn = MySpecificSliceOfType.DoStuff(currentStrignParamterValue);
        break;
}

The point being illustrated here is even stronger when you have > 2 different types.

And interfaces and abstract classes combine nicely with the C# type checking stuff too.

Interfaces are a fundamental in Reflection ... something to be used very sparingly but understodd because it can save so much in specific cases ... and in Serialisation (a.k.a. Serialization) which can really help you fly.

Aidanapword
Thank you for the detailed response. I would mark this as the answer but roufamatic beat you to it.
Mitchell Skurnik
Mitchell, thanks. I do hope it helped. I am always at awe of the power inside the CLR that - even - the Microsofot boys don't use. The Microsoft way is to early bind everything, and get the compiler to check everything. Flexibility in late binding deserialised types and careful class structures supporting this can be very valuable. But should be deployed very carefully/specifically. Steven is right ... maintainability is important.
Aidanapword