Writing Clean Code in C# and .NET
About.ME • Senior Consultant @CodeValue • Developing software (Professionally) since 2002 • Writing clean code since 2009 • Blogger: http://blog.drorhelper.com
Let’s talk about software bugs
Bugs cost around $312 Billion Per Year
And it’s all a developer’s fault
The cost of fixing bugs 1 2 10 20 50 150 RQUIRMENTS DESIGN CODE DEV T ACC T OPERATION [B. Boehm - ICSE 2006 Keynote Address]
High quality code is: • Easy to read and understand • Impossible to hide bugs • Easy to extend • Easy to change • Has unit tests Be a proud of your code
Broken windows
The cost of owning a mess 0 10 20 30 40 50 60 70 80 90 100 Productivity Productivity [Robert Martin – “Clean Code”]
Quality == Agility • Adapt to changes • Don’t be held back by bugs • Cannot be agile without high quality code
How a developer spends his time 60% - 80% time spent in understanding code So make sure your code is readable But what is a readable code?
“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live”
Megamoth Stands for MEGA MOnolithic meTHod. Often contained inside a God Object, and usually stretches over two screens in height. Megamoths of greater size than 2k LOC have been sighted. Beware of the MEGAMOTH! http://blog.codinghorror.com/new-programming-jargon/
Write short methods – please! • It’s easier to understand • Performance won’t suffer • Avoid mixing abstraction layers • Enable re-use • Also write small classes
How can we recognize bad code? • You know it we you see it • You feel it when you write it • You get used to it after a while  • known as Code Smells
Code Smells • Duplicate code • Long method • Large class • Too many parameters • Feature envy • Inappropriate intimacy • Refused request • Lazy class/Freeloader • Contrived complexity • Naming! • Complex Conditionals • And more… http://en.wikipedia.org/wiki/Code_smell
Comments often are used as a deodorant Refactoring, Martin Fowler
Comments are a dead giveaway • If explains how things done means that the developer felt bad about the code • “Code title” – should be a method • Commented Old code – SCM Good comments exist in the wild – but rare
http://stackoverflow.com/questions/184618/what-is-the-best-comment-in- source-code-you-have-ever-encountered /// <summary> /// Gets or sets the name of the first. /// </summary> /// <value>The name of the first.</value> public string FirstName } get { return _firstName; } set { _firstName = value; } { /** Logger */ private Logger logger = Logger.getLogger(); /// <summary> /// The possible outcomes of an update operation (save or delete) /// </summary> public enum UpdateResult } /// <summary> /// Updated successfully /// </summary> Success = 0, /// <summary> /// Updated successfully /// </summary> Failed = 1 { //private instance variable for storing age public static int age; // Always returns true. public bool isAvailable() } return false; {
Regions == Comments
Naming is important d, days  daysSinceLastPayment customerPo  customerPurchaseOrder productIdString  productId genymdhms  generationTimeStamp
Dead Code • Code which is never run • But still has maintenance costs • Solution - delete
Undead Code Dead code that you’re afraid to delete - “I might need this…” geek-and-poke.com/ // UNUSED // Separate into p_slidoor.c? #if 0 // ABANDONED TO THE MISTS OF TIME!!! // // EV_SlidingDoor : slide a door horizontally // (animate midtexture, then set noblocking line) //
Avoid duplicate code (DRY) “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system” The Pragmatic Programmer: Dave Thomas, Andy Hunt
public bool HasGroup(List<Token> tokenList){ for(Token token : tokemList){ if(token.get_group() != null) { return true; { { return false; { public Group GetValidGroup(List<Customer> customers){ for(Customer customer : customers){ Group group = customer.get_group(); if(group != null) { return group; { { return null; {
Good code start with good design Bad DesignGood design RigidLoosely coupled FragileHighly cohesive ImmobileEasily composable ViscousContext independent It’s all about dependencies • In .NET Reference == dependency • Change in dependency  change in code
This is not OOP!!! public class Record_Base { public DateTime RecordDateTime { get { return _recordDateTime; } set { if (this.GetType().Name == "Record_PartRegister") _recordDateTime = value; else throw new Exception("Cannot call set on RecordDateTime for table " + this.GetType().Name); } } } http://thedailywtf.com/Articles/Making-Off-With-Your-Inheritance.aspx
Design stamina hypothesis http://martinfowler.com/bliki/DesignStaminaHypothesis.html
Principles of Object Oriented Design Single responsibility Open/closed Liskov substitution Interface segregation Dependency inversion www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
Single responsibility A class should have one, and only one, reason to change. http://www.amazon.com/Wenger- 16999-ssiwS-efinK- B/pd/tnaiG001 DZTJRQ/
Naming as code smell Having difficulties naming your class/method? You might be violating SRP
public interface ITimerService { IDisposable SetTimout(long durationMilliSeconds, Action callback); Task Delay(TimeSpan delay, CancellationToken token); void KillLastSetTimer(); } public interface IDispacherTimerService : ITimerService { long GetMilisecondsFromLastStart(); } public interface IElapsedTimerService : ITimerService { void SetTimout(long durationMilliSeconds, Action<TimeSpan> callback); }
Open closed principle software entities should be open for extension, but closed for modification
Liskov subtitution objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program
LSP smell - look for type checking void ArrangeBirdInPattern(IBird aBird) } var aPenguin = aBird as Pinguin; if (aPenguin != null) } ArrangeBirdOnGround(aPenguin); { else } ArrangeBirdInSky(aBird); { // What about Emu? {
Interface segregation Many client specific interfaces are better than one general purpose interface. http://en.wikipedia.org/wiki/Cockpit
Dependency Inversion Depend upon abstractions. Do not depend upon concretions.
Your code will change! • Requirements change • Bugs are found • New feature requests  Your design will change
In the beginning… Application was beautiful - then came change… • Software Rot – Duplication – Excess coupling – Quick fixes – Hacks
public override void HandleActionRejected(User from, reason reason) } Logger.Info("HandleActionRejected - user:{0}", from.Id); /*foreach (var user in UserRepository.GetAllUsers) } Client.SendInfo(user, from, reason); { */ //2.2 Events.Users.Value = new UserData } SessionId = CurrentSession.Id, HaveIInitiated = true, OtherUser = from, StartCallStatus = Events.ConvertToCallStatus(answer) {; UserRepository.Remove(from, reason); if(UserRepository.IsEmpty()) } Exit(); { {
Refactoring
Refactoring “a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior” - Martin Fowler http://refactoring.com/catalog/
Refactoring with Visual Studio
Code reviews Can catch up to 60% of defects Effective code reviews are: • Short – don’t waste time • Constructive • Avoid emotionally draining arguments Everybody reviews and everybody is reviewed
No quality has very high cost Never have time to do it, but always have time to re-do it. Explain why this feature takes so much time “You rush a miracle man, you get rotten miracles.”
Don’t expect your company to force you Be a professional Care about your code
Improve your code • Start as soon as you can • Don’t compromise Schedule time for quality –Improve existing code –Make it work, then make it better 49
Writing clean code in C# and .NET

Writing clean code in C# and .NET

  • 1.
    Writing Clean Codein C# and .NET
  • 2.
    About.ME • Senior Consultant@CodeValue • Developing software (Professionally) since 2002 • Writing clean code since 2009 • Blogger: http://blog.drorhelper.com
  • 3.
    Let’s talk aboutsoftware bugs
  • 4.
    Bugs cost around$312 Billion Per Year
  • 5.
    And it’s alla developer’s fault
  • 6.
    The cost offixing bugs 1 2 10 20 50 150 RQUIRMENTS DESIGN CODE DEV T ACC T OPERATION [B. Boehm - ICSE 2006 Keynote Address]
  • 7.
    High quality codeis: • Easy to read and understand • Impossible to hide bugs • Easy to extend • Easy to change • Has unit tests Be a proud of your code
  • 8.
  • 9.
    The cost ofowning a mess 0 10 20 30 40 50 60 70 80 90 100 Productivity Productivity [Robert Martin – “Clean Code”]
  • 10.
    Quality == Agility •Adapt to changes • Don’t be held back by bugs • Cannot be agile without high quality code
  • 11.
    How a developerspends his time 60% - 80% time spent in understanding code So make sure your code is readable But what is a readable code?
  • 12.
    “Always code asif the guy who ends up maintaining your code will be a violent psychopath who knows where you live”
  • 13.
    Megamoth Stands for MEGAMOnolithic meTHod. Often contained inside a God Object, and usually stretches over two screens in height. Megamoths of greater size than 2k LOC have been sighted. Beware of the MEGAMOTH! http://blog.codinghorror.com/new-programming-jargon/
  • 14.
    Write short methods– please! • It’s easier to understand • Performance won’t suffer • Avoid mixing abstraction layers • Enable re-use • Also write small classes
  • 15.
    How can werecognize bad code? • You know it we you see it • You feel it when you write it • You get used to it after a while  • known as Code Smells
  • 16.
    Code Smells • Duplicatecode • Long method • Large class • Too many parameters • Feature envy • Inappropriate intimacy • Refused request • Lazy class/Freeloader • Contrived complexity • Naming! • Complex Conditionals • And more… http://en.wikipedia.org/wiki/Code_smell
  • 17.
    Comments often areused as a deodorant Refactoring, Martin Fowler
  • 18.
    Comments are adead giveaway • If explains how things done means that the developer felt bad about the code • “Code title” – should be a method • Commented Old code – SCM Good comments exist in the wild – but rare
  • 19.
    http://stackoverflow.com/questions/184618/what-is-the-best-comment-in- source-code-you-have-ever-encountered /// <summary> /// Getsor sets the name of the first. /// </summary> /// <value>The name of the first.</value> public string FirstName } get { return _firstName; } set { _firstName = value; } { /** Logger */ private Logger logger = Logger.getLogger(); /// <summary> /// The possible outcomes of an update operation (save or delete) /// </summary> public enum UpdateResult } /// <summary> /// Updated successfully /// </summary> Success = 0, /// <summary> /// Updated successfully /// </summary> Failed = 1 { //private instance variable for storing age public static int age; // Always returns true. public bool isAvailable() } return false; {
  • 20.
  • 21.
    Naming is important d,days  daysSinceLastPayment customerPo  customerPurchaseOrder productIdString  productId genymdhms  generationTimeStamp
  • 22.
    Dead Code • Codewhich is never run • But still has maintenance costs • Solution - delete
  • 23.
    Undead Code Dead codethat you’re afraid to delete - “I might need this…” geek-and-poke.com/ // UNUSED // Separate into p_slidoor.c? #if 0 // ABANDONED TO THE MISTS OF TIME!!! // // EV_SlidingDoor : slide a door horizontally // (animate midtexture, then set noblocking line) //
  • 24.
    Avoid duplicate code(DRY) “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system” The Pragmatic Programmer: Dave Thomas, Andy Hunt
  • 25.
    public bool HasGroup(List<Token>tokenList){ for(Token token : tokemList){ if(token.get_group() != null) { return true; { { return false; { public Group GetValidGroup(List<Customer> customers){ for(Customer customer : customers){ Group group = customer.get_group(); if(group != null) { return group; { { return null; {
  • 26.
    Good code startwith good design Bad DesignGood design RigidLoosely coupled FragileHighly cohesive ImmobileEasily composable ViscousContext independent It’s all about dependencies • In .NET Reference == dependency • Change in dependency  change in code
  • 27.
    This is notOOP!!! public class Record_Base { public DateTime RecordDateTime { get { return _recordDateTime; } set { if (this.GetType().Name == "Record_PartRegister") _recordDateTime = value; else throw new Exception("Cannot call set on RecordDateTime for table " + this.GetType().Name); } } } http://thedailywtf.com/Articles/Making-Off-With-Your-Inheritance.aspx
  • 28.
  • 29.
    Principles of ObjectOriented Design Single responsibility Open/closed Liskov substitution Interface segregation Dependency inversion www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
  • 30.
    Single responsibility A classshould have one, and only one, reason to change. http://www.amazon.com/Wenger- 16999-ssiwS-efinK- B/pd/tnaiG001 DZTJRQ/
  • 31.
    Naming as codesmell Having difficulties naming your class/method? You might be violating SRP
  • 32.
    public interface ITimerService { IDisposableSetTimout(long durationMilliSeconds, Action callback); Task Delay(TimeSpan delay, CancellationToken token); void KillLastSetTimer(); } public interface IDispacherTimerService : ITimerService { long GetMilisecondsFromLastStart(); } public interface IElapsedTimerService : ITimerService { void SetTimout(long durationMilliSeconds, Action<TimeSpan> callback); }
  • 33.
    Open closed principle softwareentities should be open for extension, but closed for modification
  • 35.
    Liskov subtitution objects ina program should be replaceable with instances of their subtypes without altering the correctness of that program
  • 36.
    LSP smell -look for type checking void ArrangeBirdInPattern(IBird aBird) } var aPenguin = aBird as Pinguin; if (aPenguin != null) } ArrangeBirdOnGround(aPenguin); { else } ArrangeBirdInSky(aBird); { // What about Emu? {
  • 37.
    Interface segregation Many clientspecific interfaces are better than one general purpose interface. http://en.wikipedia.org/wiki/Cockpit
  • 38.
    Dependency Inversion Depend uponabstractions. Do not depend upon concretions.
  • 39.
    Your code willchange! • Requirements change • Bugs are found • New feature requests  Your design will change
  • 40.
    In the beginning… Applicationwas beautiful - then came change… • Software Rot – Duplication – Excess coupling – Quick fixes – Hacks
  • 41.
    public override voidHandleActionRejected(User from, reason reason) } Logger.Info("HandleActionRejected - user:{0}", from.Id); /*foreach (var user in UserRepository.GetAllUsers) } Client.SendInfo(user, from, reason); { */ //2.2 Events.Users.Value = new UserData } SessionId = CurrentSession.Id, HaveIInitiated = true, OtherUser = from, StartCallStatus = Events.ConvertToCallStatus(answer) {; UserRepository.Remove(from, reason); if(UserRepository.IsEmpty()) } Exit(); { {
  • 42.
  • 43.
    Refactoring “a disciplined techniquefor restructuring an existing body of code, altering its internal structure without changing its external behavior” - Martin Fowler http://refactoring.com/catalog/
  • 44.
  • 45.
    Code reviews Can catchup to 60% of defects Effective code reviews are: • Short – don’t waste time • Constructive • Avoid emotionally draining arguments Everybody reviews and everybody is reviewed
  • 46.
    No quality hasvery high cost Never have time to do it, but always have time to re-do it. Explain why this feature takes so much time “You rush a miracle man, you get rotten miracles.”
  • 47.
    Don’t expect yourcompany to force you Be a professional Care about your code
  • 48.
    Improve your code •Start as soon as you can • Don’t compromise Schedule time for quality –Improve existing code –Make it work, then make it better 49

Editor's Notes

  • #6 The developer Wrote the code - Was the first to see the feature Can validate requirments
  • #7 So why not have better testing? It’s hard to find all of the scenarios Cost of fixing increase
  • #10 Bad code attracts more bad code “It was like this when I got here”
  • #13 Show example of not readable code
  • #15 a.k.a spaghetti code
  • #27 Avoid duplicate code (DRY)