Your SlideShare is downloading. ×
Clean Code Development
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Clean Code Development

2,624
views

Published on

Good and Bad Code …

Good and Bad Code
The Broken Window Theory
The Grand Redesign in the Sky
The Sushi Chef Rule
The Hotel Room Rule
The Boy Scout Rule

OOP Patterns and Principles
SOLID Principles

How to measure clean code?
Tools

Published in: Technology

1 Comment
1 Like
Statistics
Notes
  • Nice presentation. Another habit that does wonders is choosing good names. However, this is obviously not always easy: http://martinfowler.com/bliki/TwoHardThings.html
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
2,624
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
73
Comments
1
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • http://blog.gfader.com
  • Click to add notes...Peter Gfader http://blog.gfader.com
  • Z1 1936ENIAC 1943, ..
  • Z1 1936ENIAC 1943, ..
  • Z1 1936ENIAC 1943, ..
  • Z1 1936ENIAC 1943, ..
  • Adams theory on this is: “We will have an exponential growth as soon as code is writing code”
  • Open Word and get suggestions!CorrectnessUsabilityEfficiencyReliabilityIntegrityAdaptabilityAccuracyRobustness Maintainability FlexibilityPortabilityReusabilityReadabilityTestabilityUnderstandabilityNot too many WTFsEasy to readEasy to maintainConsistent convention (naming, layout, design patterns)Follows SSW rulesCode Auditor 0No bugsDoes what it should do (Client’s needs)Easy to changeWritten in a language, that you can find dev's forPerformance
  • Who is a dev? Testers? BA's? PM's?
  • This is a VB programmer, so he probably needs that
  • HTML spew, I don’t say more… beginner devs underneath covers
  • Less code = less code to read?Shorter code = faster?Shorter code = less memory?
  • To get things done?Speed?Meeting Deadlines?Taking Shortcuts..But after too many shortcuts there is no progress...
  • DBASE was terrible!Look up wikipedia
  • Sushi Chef rule - Clean up as you doThe Sushi Chef has done this certain routine of hand movements already 100 times before.He is just following this routine.He cleans up as he does his jobs.#1 Software devs do something slightly different every day#2 Devs want to get something done. The brain is in "Get done mode". Clean up later
  • What is code?Stuff that a machine reads
  • High cohesion - better understandability, robustnessLow coupling - better maintainability, high resistance to changes
  • Naming: Better?IAuthenticationProviderIMembershipProviderIPasswordProvider
  • StyleCop: Great for your team! Agree on your team style and stick to itCode Analysis
  • StyleCop: Great for your team! Agree on your team style and stick to itCode Analysis
  • Transcript

    • 1. Clean Code Development Peter Gfader #netug Delivering Awesome Web Applications
    • 2. C# and .NET (Java not anymore) Testing Automated tests Agile, Scrum Scrum Developer Trainer Technology aficionado Silverlight ASP.NET Windows Forms LINQ, ... Peter Gfader http://blog.gfader.com/ twitter.com/peitor #netug
    • 3. • Why code matters • Good and Bad Code • The Broken Window Theory • The Grand Redesign in the Sky • The Boy Scout Rule • OOP Patterns and Principles • SOLID Principles • How to measure clean code? •Tools Agenda
    • 4. 1903 Wright brothers flew 59 seconds Why code matters? http://www.reddit.com/r/AskReddit/comments/dlrjs/whats_the_most_mindblowing_fact_you_heardread_in/
    • 5. 1969 We landed on the moon Why code matters?
    • 6. Today We fly around the world in 32 hours Tourists in space Why code matters?
    • 7. 1903 - 0 computers Why code matters?
    • 8. 40 years later - a handful of computers Why code matters?
    • 9. Today > 500 billion programmable devices Why code matters?
    • 10. Today > 500 billion programmable devices (more than humans on earth) Why code matters?
    • 11. 2100 Programmable devices everywhere Under skin, in brain, in blood… like dust… Why code matters?
    • 12. Who programs those? Why code matters?
    • 13. Why code matters? What tools do we use?
    • 14. Why code matters? Can we trust our code? Important?
    • 15. What is good code?
    • 16. It's gotta ship? It's gotta pass the tester? It's gotta implement requirements? It's gotta be reasonably performant? "Wartung"? (aka Maintainability) What is good code?
    • 17. What is bad code?
    • 18. What is bad code?
    • 19. What is bad code?
    • 20. while ((!found) && (pos < (fileContent.Length - 6))) { byteData = new byte[6]; Array.Copy(fileContent, pos, byteData, 0, 6); pos = pos + 6; str_byteData = enc.GetString(byteData); if (str_byteData.Contains("s")) { posE_byteData = str_byteData.IndexOf("s"); pos = pos + (posE_byteData - 6); Array.Copy(fileContent, pos, byteData, 0, 6); pos = pos + 6; if (byteData[0] == 0x73) // 's' { if (byteData[1] == 0x74) // 't' { if (byteData[2] == 0x72) // 'r' { if (byteData[3] == 0x65) // 'e' { if (byteData[4] == 0x61) // 'a' { if (byteData[5] == 0x6D) // 'm' { found = true; break; } else { if (byteData[5] == 0x73) { pos = pos - 1; } } } What is bad code?
    • 21. public int x() { int q = 0; int z = 0; for (int kk = 0; kk < 10; kk++) { if (l[z] == 10) { q += 10 + (l[z + 1] + l[z + 2]); z += 1; } else if (l[z] + l[z + 1] == 10) { q += 10 + l[z + 2]; z += 2; } else { q += l[z] + l[z + 1]; z += 2; } } return q; } What is bad code?
    • 22. What is bad code?
    • 23. • Hard to understand at first sight • Unmaintained • Messy • No one cares What is bad code?
    • 24. • Hard to understand at first sight • Unmaintained • Messy • No one cares "Wartung"? (aka Maintainabilty) What is bad code?
    • 25. Bad Code Is SCARY!!!
    • 26. Why are we writing bad code?
    • 27. Broken Window Theory
    • 28. Broken Window Theory
    • 29. The rewrite
    • 30. Netscape rewrote Netscape 4.0 and released it after three years as Netscape 6.0
    • 31. Borland rewrote dBase and Quattro Pro
    • 32. Microsoft Rewrote Vista ~60%
    • 33. What can we do?
    • 34. Sushi chef rule Clean up as you do
    • 35. Hotel room rule Let someone clean up every day
    • 36. The Boy Scout Rule Leave the campground cleaner than you found it
    • 37. How can we improve?
    • 38. "Everything I have to change, in order to make the product owner happy!" • Config files .config, .svc • XAML .xaml, .CSS, .. • Code .cs, .vb, .js, .. • Deployment scripts .ps • Batch files .bat What is code?
    • 39. OOP Principles
    • 40. Solid PrinciplesS.o.l.i.d. Principles
    • 41. Single Responsibility Principle Only one reason to change Robustness Focus Every entity should have a single responsibility
    • 42. public class PrintServer { public string CreateJob(PrintJob data) { //... } public int GetStatus(string jobId) { //... } public void Print(string jobId, int startPage, int endPage) { //... } public List<Printer> GetPrinterList() { //... } public bool AddPrinter(Printer printer) { //... } public event EventHandler<JobEvent> PrintPreviewPageComputed; public event EventHandler PrintPreviewReady; // ... }
    • 43. public class PrintServer { public string CreateJob(PrintJob data) { //... } public int GetStatus(string jobId) { //... } public void Print(string jobId, int startPage, int endPage) { //... } } public class PrinterList { public List<Printer> GetPrinterList() { //... } public bool AddPrinter(Printer printer) { //... } }
    • 44. OpenClose Principle Open for extension Close for modification Every entity should be open for extension, but closed for modification
    • 45. public void SaveToolbarStateSwitch() { long version = Core.GetVisualStudioVersion(); Configuration.VSToolbarHeight = AddinCommandBar.Height.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); switch (version) { case 2003: case 2004: case 2005: Configuration.VSToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); break; case 2008: Configuration.VSToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); break; case 2010: Configuration.VSToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VSToolbarLeft = AddinCommandBar.Left.ToString(); Configuration.VSToolbarTop = AddinCommandBar.Top.ToString(); Configuration.VSToolbarWidth = AddinCommandBar.Width.ToString(); break; default: Configuration.VS2010ToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VS2010ToolbarPosition = AddinCommandBar.Position.ToString(); break; }
    • 46. public class ToolbarManager { public void SaveToolbarState() { var version = Core.GetVisualStudioVersion(); Configuration.VSToolbarHeight = AddinCommandBar.Height.ToString(); if (version <= 2003) { Configuration.VS2010ToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VS2010ToolbarPosition = AddinCommandBar.Position.ToString(); } else if (version >= 2005 && version <= 2008) { Configuration.VSToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); } else if (version == 2010) { Configuration.VSToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VSToolbarLeft = AddinCommandBar.Left.ToString(); Configuration.VSToolbarTop = AddinCommandBar.Top.ToString(); Configuration.VSToolbarWidth = AddinCommandBar.Width.ToString(); } else { Configuration.VSToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); } }
    • 47. private void SaveForVs2003() { Configuration.VSToolbarVisible = "False"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); } private void SaveForVs2005() { Configuration.VSToolbarVisible = "True"; Configuration.VSToolbarPosition = ((int)AddinCommandBar.Position).ToString(); Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); Configuration.VS2010ToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; } private void SaveForVs2008() { Configuration.VSToolbarPosition = "False"; Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarVisible = "False"; Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); } private void SaveForVs2010() { Configuration.VSToolbarVisible = AddinCommandBar.Visible ? "True" : "False"; Configuration.VSToolbarPosition = "False"; Configuration.VS2010ToolbarRowIndex = AddinCommandBar.RowIndex.ToString(); Configuration.VS2010ToolbarWidth = AddinCommandBar.Width.ToString(); Configuration.VS2010ToolbarHeight = AddinCommandBar.Height.ToString(); }
    • 48. public class ToolbarManager { private readonly Dictionary<long, Action> _versionAction; public ToolbarManager() { _versionAction = new Dictionary<long, Action>(); _versionAction.Add(2003, SaveForVs2003); _versionAction.Add(2005, SaveForVs2005); _versionAction.Add(2008, SaveForVs2008); _versionAction.Add(2010, SaveForVs2010); } public void SaveToolbarStateBetter() { var version = Core.GetVisualStudioVersion(); if (_versionAction.ContainsKey(version)) { _versionAction[version].Invoke(); } }
    • 49. public class ToolbarManager { private readonly Dictionary<long, Action> _versionAction; public ToolbarManager() { _versionAction = new Dictionary<long, Action>(); _versionAction.Add(2003, SaveForVs2003); _versionAction.Add(2005, SaveForVs2005); _versionAction.Add(2008, SaveForVs2008); _versionAction.Add(2010, SaveForVs2010); _versionAction.Add(2012, SaveForVs2012); } private void SaveForVs2012() { Configuration.EnableSpeechRecognition = "True"; Configuration.HandGestureRecognition = AddinCommandBar.Top; }
    • 50. Liskov Substitution Principle If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T
    • 51. Liskov Substitution Principle Subtypes must be substitutable for their base types Inheritance and polymorphism
    • 52. public class Rectangle { public int Width { get; set; } public int Height { get; set; } public int GetArea() { return Width*Height; } }
    • 53. [TestFixture] public class RectangleTests { [Test] public void CheckArea_PassingTest() { Rectangle r = new Rectangle(); CheckAreaOfRectangle(r); } private void CheckAreaOfRectangle(Rectangle r) { r.Width = 5; r.Height = 2; Assert.AreEqual(10, r.GetArea()); } }
    • 54. We need a Square!
    • 55. public class Rectangle { protected int _width; public virtual int Width { get { return _width; } set { _width = value; } } protected int _height; public virtual int Height { get { return _height; } set { _height = value; } } public int GetArea() { return Width*Height; } } public class Square : Rectangle { public override int Width { get { return _width; } set { _width = value; _height = value; } } public override int Height { get { return _height; } set { _height = value; _width = value; } } }
    • 56. [TestFixture] public class RectangleTests { [Test] public void CheckArea_PassingTest() { Rectangle r = new Rectangle(); CheckAreaOfRectangle(r); } private void CheckAreaOfRectangle(Rectangle r) { r.Width = 5; r.Height = 2; Assert.AreEqual(10, r.GetArea()); } [Test] public void CheckArea_FAILINGTest() { Rectangle r = new Square(); CheckAreaOfRectangle(r); } }
    • 57. public class Rectangle { public int Width { get; set; } public int Height { get; set; } public int GetArea() { return Width * Height; } } public class Square { public int Side { get; set; } public int GetArea() { return Side * Side; } }
    • 58. Interface Segregation Principle Don’t be force to implement unused methods Avoid “Fat Interfaces” Clients should not be forced to depend on methods they do not use
    • 59. public override bool ValidateUser(string usercode, string password) { var returnValue = false; MoneyService moneyServices = new MoneyService(); if (moneyServices.IsValid(usercode, password)) { returnValue = true; } return returnValue; } -- snip snip snip ---- public class MoneyMembershipProvider : MembershipProvider {
    • 60. namespace System.Web.Security { public abstract class MembershipProvider : ProviderBase { public abstract bool EnablePasswordRetrieval { get; } public abstract bool EnablePasswordReset { get; } public abstract bool RequiresQuestionAndAnswer { get; } public abstract string ApplicationName { get; set; } public abstract int MaxInvalidPasswordAttempts { get; } public abstract int PasswordAttemptWindow { get; } public abstract bool RequiresUniqueEmail { get; } public abstract MembershipPasswordFormat PasswordFormat { get; } public abstract int MinRequiredPasswordLength { get; } public abstract int MinRequiredNonAlphanumericCharacters { get; } public abstract string PasswordStrengthRegularExpression { get; } public abstract MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status); public abstract bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer); public abstract string GetPassword(string username, string answer); public abstract bool ChangePassword(string username, string oldPassword, string newPassword); public abstract string ResetPassword(string username, string answer); public abstract void UpdateUser(MembershipUser user); public abstract bool ValidateUser(string username, string password); public abstract bool UnlockUser(string userName); public abstract MembershipUser GetUser(object providerUserKey, bool userIsOnline); public abstract MembershipUser GetUser(string username, bool userIsOnline); public abstract string GetUserNameByEmail(string email); public abstract bool DeleteUser(string username, bool deleteAllRelatedData); public abstract MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords); public abstract int GetNumberOfUsersOnline(); public abstract MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords); public abstract MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords); protected virtual byte[] EncryptPassword(byte[] password);
    • 61. public class AuctionsPlusMembershipProvider : MembershipProvider { -- snip snip snip ---- public override bool ChangePassword(string username, string oldPassword, string newPassword) { throw new NotImplementedException(); } public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPa { throw new NotImplementedException(); } public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passw { throw new NotImplementedException(); } public override bool DeleteUser(string username, bool deleteAllRelatedData) { throw new NotImplementedException(); } public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecord { throw new NotImplementedException(); } public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalReco { throw new NotImplementedException(); } public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }
    • 62. public interface IEnableUservalidation { bool ValidateUser(string username, string password); } public interface IAllowUserRetrieval { MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords); MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords); MembershipUser GetUser(object providerUserKey, bool userIsOnline); MembershipUser GetUser(string username, bool userIsOnline); string GetUserNameByEmail(string email); MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords); int GetNumberOfUsersOnline(); } public interface IProvidePassword { bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer); bool ChangePassword(string username, string oldPassword, string newPassword); string ResetPassword(string username, string answer); string GetPassword(string username, string answer); }
    • 63. Dependency Inversion Principle Depend on Abstractions Interfaces, not concrete types Inject Dependencies into Classes Inversion of Control Hollywood Principle: "Don't call us, We call you" I tell an object its partners, and not the object chooses its partners
    • 64. public class WCFSalaryService { private IDBHelper dbHelper = new SQLHelper(); private ILoggerHelper loggerHelper = new FileLogWriter(); private IAuthenticationHelper authenticationHelper = new WebServiceAuth(); private IUserUtility userHelper; private IConnections connectionHelper = new HTTPConnectionHelper(); public WCFSalaryService() { userHelper = new UserHelper(connectionHelper); userHelper.Logger = loggerHelper; dbHelper.Logger = loggerHelper; // ----- snip snip snip ---- } // ----- snip snip snip ---- }
    • 65. private IDBHelper _dbHelper; private ILoggerHelper _loggerHelper; private IAuthenticationHelper _authenticationHelper; private IUserUtility _userHelper; private IConnections _connectionHelper; public WCFSalaryService( IDBHelper dbHelper, ILoggerHelper loggerHelper, IAuthenticationHelper authenticationHelper, IUserUtility userHelper, IConnections connectionHelper) { _dbHelper = dbHelper; _loggerHelper = loggerHelper; _authenticationHelper = authenticationHelper; _userHelper = userHelper; _connectionHelper = connectionHelper;
    • 66. private IDBHelper _dbHelper; private ILoggerHelper _loggerHelper = new FileLogWriter(); private IAuthenticationHelper _authenticationHelper = new WebserviceAuth(); private IUserUtility _userHelper; private IConnections _connectionHelper; public WCFSalaryService( IDBHelper dbHelper, ILoggerHelper loggerHelper, IAuthenticationHelper authenticationHelper, IUserUtility userHelper, IConnections connectionHelper) { _userHelper = new UserHelper(connectionHelper); _userHelper.Logger = loggerHelper; if (authenticationHelper != null) { _authenticationHelper = authenticationHelper; } if (dbHelper != null) { _connectionHelper.DbHelper = dbHelper; _authenticationHelper.DbHelper = dbHelper; } else { _connectionHelper.DbHelper = DBHelper.Instance; _authenticationHelper.DbHelper = DBHelper.Instance; } if (loggerHelper != null) { this._loggerHelper = loggerHelper; } _userHelper.LoggerHelper = this._loggerHelper; _authenticationHelper.LoggerHelper = this._loggerHelper; _connectionHelper.LoggerHelper = this._loggerHelper; // ----- snip snip snip ---- }
    • 67. public class SalaryScenario : NinjectModule { public override void Load() { Bind<ILoggerHelper>().To<FileLogWriter>(); Bind<IDBHelper>().To<SQLHelper>(); Bind<IAuthenticationHelper>().To<WebServiceAuth>(); Bind<IUserUtility>().To<UserUtility>(); Bind<IConnections>().To<HTTPConnectionHelper>(); } } public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { IKernel kernel = new StandardKernel (new SalaryScenario()); var logger = kernel.Get<ILoggerHelper>(); logger.LogIt("App started up"); }
    • 68. Solid PrinciplesS.o.l.i.d. Principles
    • 69. Adam: "What you cant measure you cant improve!" Measure clean code
    • 70. • Dependency Diagrams (VS2010) • StyleCop • Code Analysis (VS2010) • Code Metrics (VS2010) • Nitriq Tools!
    • 71. • Code Auditor • ReSharper / CodeRush / Refactor Pro • Atomiq • SourceMonitor • NDepend And more... More Tools!
    • 72. No tool can replace a code review
    • 73. "Writing code a computer can understand is science. Writing code other programmers can understand is an art." Jason Gorman Its not easy
    • 74. From now on...
    • 75. Readable Code
    • 76. Tests
    • 77. Avoid Duplication
    • 78. • Readable • Tests in place • No duplication "Wartung" What is clean code?
    • 79. • Why code matters • Good and Bad Code • The Broken Window Theory • The Grand Redesign in the Sky • The Boy Scout Rule • OOP Patterns and Principles • SOLID Principles • How to measure clean code? •Tools Summary
    • 80. Further Reading
    • 81. Further Reading
    • 82. Further Reading
    • 83. Further Reading
    • 84. http://www.clean-code-developer.de/
    • 85. VS2010 Code Metrics http://bit.ly/bda4T1 JB Rainsberger The Four Elements of Simple Design http://www.jbrains.ca/permalink/the-four-elements-of-simple-design How to hire a programmer? Have people fix up some smelly code http://codebetter.com/blogs/karlseguin/archive/2006/12/01/How-to-hire-a-programmer- _2D00_-Part-2-_2D00_-Improve-this-code.aspx C# Coding Practices http://www.codeproject.com/KB/cs/CSharp_Coding_Practices.aspx Object Oriented Principles http://www.objectmentor.com/omSolutions/oops_what.html Further Reading
    • 86. http://www.refactoring.com/ http://refactormycode.com/ All links and slides on http://blog.gfader.com/ Further Doing
    • 87. VS2010 http://msdn.microsoft.com/en-us/vstudio/ Nitriq & Atomiq http://nimblepros.com/products.aspx SourceMonitor http://www.campwoodsw.com/sourcemonitor.html Ndepend http://www.ndepend.com/ Tools References
    • 88. Better Software An introduction to good code Giordano Scalzo, 06/05/2009 Thanks to Giordano!
    • 89. http://creativecommons.org/licenses/by-nc-sa/3.0/
    • 90. Be a boy scout Leave the campground cleaner than you found it
    • 91. Be a boy scout Leave code cleaner than you found it All links and slides on http://blog.gfader.com Thank you!!!