Showing posts with label readibility. Show all posts
Showing posts with label readibility. Show all posts

First steps with Machine.Specifications (BDD framework)

Old machine. Where is the specification?
Figure: How do you specify this machine?

As you may have read in my previous blog post: On the road to BDD… Or… to see the light, I am dabbling more and more into the ATDD / BDD world.

These are my impressions from Machine.Specifications.
BTW: Gread video from JP Boodhoo about Getting up and running with MSpec

Code52 Show and Tell: My pet project CopyCat - Lessons learned

CopyCat – A big fat cat walking and waltzing the internetz

Figure: CopyCat – A big fat cat walking and waltzing the internetz
 

I am a pretty normal geek. At least I think I am normal and a geek. I see geeks as people (yes really) that want to play with things, discover new things and build things. When geeks play with things they discover new things quite often.
(Similar story heard and “adapted” from Scott Hanselman) 
After I ‘ve discovered something I want to scream it out to someone:

“Look at this dude!! Isn’t that awesome???”

A normal reaction that you get from a non-geek:

“Wow… Is this showing the weather in form of colors that you could just get by watching out the window?”

This is the pattern for the reaction that you normally get
“Wow… Is this <something> that does <somethingUselessAtBeginning> that you could just get by doing <somethingElse>?”

On the road to BDD… Or… to see the light

If you are a regular reader of this little blog in the middle of the internet, you might have realized that I am keen on “all things testing”. This is just a little experience report on my journey to better testing and getting everyone involved in the discussion about what we are building with our codez.

image
Figure: Everyone get together and collaborate

Generated documentation is worse than useless (0 value) and causes pain in the future

I just came across a blog post from Ian about GhostDoc and Atominerr and had to share my thoughts here about those tools

Useless but fun.   Generated documentation is useless but not fun!
Figure: Useless but fun! 

SQL can stink too - Code smell in stored procedures

image
Figure: You don't need to dig deep to find smelly code

I just found this nice piece of TSQL that I came across in a 500 line stored procedure on my current project.

Code smell - LINQ to SQL Datacontext usage and more… - Refactoring work in progress

image
Following up the blog post about some major issues in the usage of the datacontext I dig into more details here.
Here is the initial blog post with an intro and the whole code

Lets start to look at the methods itself, starting with: "UpdateEmployeePositionHistory".

Code smell - LINQ to SQL Datacontext usage and more…

I just came across some code where I needed to fix a couple of issues in. Since I am a strong proponent of continuous improvement and refactoring I thought I blog about this good example.

 

Code contracts - Is it only about argument validation?

*Updated* 3 April 2011: Update how to enable Intellisense for code contracts

 

There are more and more articles coming out about Code Contracts. Some of them talk only about input validation and miss the goal of Code Contracts. What else can we do with Code Contracts?

image
Figure: Real world validation message


Microsoft DevLabs says: Code Contracts express coding assumptions

 

question_and_answer[5] What are coding assumptions?

The "Hotel Room Rule"

<Thoughts about Clean Code Development>
As a  Clean Code Developer we should follow the "Boy Scout Rule", that says: "Check-in our code a little cleaner than when we checked it out".

Additionally to the "Boy Scout Rule", Uncle Bob spoke about Sushi chefs, that clean up their work as they go and do their work. 
I call this the "Sushi Chef rule: Clean up as you do".

image
Figure: Sushi Chef Rule: "Clean up as you do"

The problem with that in my eyes is, that this "rule" is not applicable in Software development.
As a developer we want to get the job done as quickly as possible. "Hacking away / getting something" done and "cleaning up" are 2 different modes on how we work and think. Switching between these 2 modes is not easy, because its almost a context switch, and switching contexts is bad. I actually tempt to think: "I fix that up later" and add a couple of "TODO" as I hack away…
Additionally when we want to get something done, we need to "get into the zone". This "zone mode" is different to the cleaning up mode, where we browse and read code.

 

I thought about this and the "Broken window theory" a little bit more and found another analogy: Hotels.
If you stay in a hotel for a week, there is some cleaning personnel that clean your room every day.

  • Why are they cleaning the room every day?
  • Why they are not just cleaning the room when I leave the hotel at the end of my holiday?

The reason is the "Broken window theory". A little mess attracts more mess, and gets a big pile of mess over time.
That lead me to the "Hotel room rule"

image
Figure: Hotel Room Rule: "Let someone else clean up your code every day"

What do you think?

  • Can we apply this principle to software?
  • Wouldn't it be nice to have someone else to clean up our mess for us?
  • Please give me an army of software cleaners that "clean" code for me?
  • Will there be a university degree or specialization in the year 2035: "Master of Software Refactoring and Code Cleaning"?

Clean Code Development talk at the #netug

image 
Thanks everyone for attending. I enjoyed last night… Special Thanks to Giordano Scalzo's whose slide I used as a base for my talk, and with who I had interesting conversations about ideas and slides…
Make sure to check the list of "good code attributes" at the end of the post. That's the list that we came up with, during the user group…

Content

  1. What
    1. Why Code matters!
    2. What is Bad?
    3. What is Good?
  2. Why
    1. The Broken Window Theory
    2. The Grand Redesign in the Sky
    3. The Sushi Chef Rule (would be nice - NA)
    4. The Hotel Room Rule (would be nice - NA)
    5. The Boy Scout Rule
  3. How
    1. OOP Patterns and Principles
    2. SOLID Principles
  4. How to measure clean code?
    Tools

 

 

PS
If you are able to apply the "Hotel Room Rule" in your projects let me know!


image
Figure: Hotel Room Rule: "Let someone else clean up your code every day"

 

 

Don't be lazy. Avoid the type "Tuple"

*Updated* 26. September 2010: Updated with comments from Adam Cogan
*Updated* 27. September 2010: Updated the comparison between anonymous types and Tuple's from blog comments
*Updated* 6. July 2017: Microsoft released C#7 that has a tuple type and tuple literal which resolves my below issues. https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/ 
Attention: From a Clean Code perspective I would consider the Primitive Obsession smell with tuples.

Tuple is a new type introduced in .NET4. My first impression of it was great, because it's a nice and easy way to group elements of a different type together. Sweet!
My first experience using the Tuple type was using it as a return value from a few methods, where I previously had an "out" parameter before, like this…
            string errormsg;
            User user;
            bool success = AuthenticationService.GetUser(usercode, out user, out errormsg);
Figure: Bad example - We should avoid "out" parameters, because it means we return 2 objects from a method.

Avoid type casts - Use the "as" operator and check for null

Note: I don't care about measuring performance on these 2 operations because we don't use them in a tight loop.
For me its all about readability and robustness of my code.

Look at these code samples doing some type casts

        public List GetJobRulesFromPhysicalDB(DataTable renewedRules)
        {
            if (renewedRules.Rows.Count > 0 && CurrentJob.JobRules.Count > 0)
            {
                foreach (DataRow row in renewedRules.Rows)
                {
                    foreach (JobRule item in CurrentJob.JobRules)
                    {
                        if ((Guid)row["RuleID"] == item.RuleId)
                        {
                            item.UpdateRule(CurrentJob.RuleRepository.GetNewRuleByRuleId(item.RuleId));
                            break;
                        }
                    }
                }
            }

            return CurrentJob.JobRules;
        }
Figure: 1 code sample with untyped datatables

 

  
        private void AMControlMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var auc = (AMUserControl)sender; 
            var aucSessionId = auc.myUserControl.Tag;
            // snip snip snip
   
        }
Figure: Event handler in Silverlight

I see this VERY often, so I had to blog about it.

Inconsistent code will bite you sooner or later - I reckon sooner ;-)

See this sample interface with some method signatures

void CalculateSalary(string environment, string emloyeeName, ...)

void GetListOfSubEmployees(string environment, string emloyeeName, ...)

void CalculateBonusPerYear(string environment, string emloyeeName, ...)

void GetOrderRegion(string environment, string emloyeeName, ...)

void UpdateEmployee(string environment, string emloyeeName, ...)

void MergePolicy(string emloyeeName, string environment, ...)

As you can see all methods have some common parameters (string environment, string emloyeeName).

ASP.NET – WTF Code smell – Request.Path.Contains

1. Read the following code and try to understand what it tries to achieve

 protected void Page_Load(object sender, EventArgs e)
 {

       if (HttpContext.Current.User.IsInRole("User "))
       {
           FormView1.FindControl("noteRow").Visible = true;
           FormView1.FindControl("RequiredFieldValidator4").Visible = false;
           // TODO: Fix this - What if Action is 2nd parameter in URL
           if (Request.Path.Contains(@"ClientProfile.aspx?Action=Add"))
           {
               FormView1.FindControl("thLoginID").Visible = true;
               FormView1.FindControl("tdLoginID").Visible = true;
               FormView1.FindControl("txtLoginID").Visible = true;
           }

       }
       else
       {
           FormView1.FindControl("noteRow").Visible = false;
       }


     if (HttpContext.Current.User.IsInRole("Administrator"))
     {

         if (!Request.Path.Contains(@"/AdministratorProfile.aspx"))
         {
             if (!Request.Path.Contains(@"/Profile.aspx"))
             {
                 FormView1.FindControl("txtLoginID").Visible = false;
                 FormView1.FindControl("lblLoginID").Visible = false;
                 -- Snip snip snip – more controls are hidden or shown -- --

                 if (Request.Path.Contains(@"/UserProfile.aspx") && HttpContext.Current.User.IsInRole("User") && (Request.QueryString["Action"] == null || Request.QueryString["Action"].Equals("New")))
                 {

                     FormView1.FindControl("thLoginID").Visible = true;
                     FormView1.FindControl("lblLoginID").Visible = true;
                     -- Snip snip snip – more controls are hidden or shown -- --

                 }
                 else
                 {
                     FormView1.FindControl("thLoginID").Visible = false;
                     FormView1.FindControl("lblLoginID").Visible = false;
                     -- Snip snip snip – more controls are hidden or shown -- --


                 }

             }
             else
             {
                 FormView1.FindControl("thDateRegistered").Visible = false;
                 FormView1.FindControl("tdDateRegistered").Visible = false;
                 -- Snip snip snip – more controls are hidden or shown -- --

             }
         }
         else if (Request.Path.Contains(@"/ReaderProfile.aspx"))
         {
             FormView1.FindControl("tdAdviser").Visible = false;
             FormView1.FindControl("thAdviser").Visible = false;
             -- Snip snip snip – more controls are hidden or shown -- --
 
         }
     }
     else if (HttpContext.Current.User.IsInRole("Administrator"))
     {
        -- Snip snip snip – this code is 130 lines long... -- --

     Figure: Code from a ASP.NET usercontrol. The usercontrol determines on which page it is used

2. Now try to image you have to fix something in this mess.

3. Or try to add a feature for a certain user.

 image

 

The only way this code is developed, is

  1. debugging (called manual testing by Roy)
  2. adding some code,
  3. debugging again,
  4. adding some code

 

My main problem here is the combination of

In particular

  • The check on URL path and query string parameters!!!
  • -->  Request.Path.Contains(@"ClientProfile.aspx?Action=Add")
    • What if Action is 2nd parameter in URL (and not the 1st one)
    • This comes from: debugging and seeing that this comes in to the control…

How can the next dev work out when we enter in which branch?

 

 ap--check   This code (control) has been fixed now and uses now properties that are set from the user of the control

My suggestions:

  • Don’t touch Request.Path.Contains method at all
  • Don’t use debugging to decide which part of the method to insert new code
  • Try to think before code :-)
  • Don’t use the debugger to much

BTW: This code broke at least two principles

  1. Single Responsibility Principle
  2. tell don’t ask principle

 

I am curious so I paste this code to VS 2010 and run “Analyze”, “Code Metrics”

  • Cyclomatic Complexity = 23. Not too bad.  EDIT: Cyclomatic Complexity = 23 = Bad.
  • Maintainability Index = 25. Not very good

 

image Figure: Cyclomatic Complexity of 23 for the Page_Load method

 

As a quick test I extract a piece of code from the Page_Load to another method and expect the Cyclomatic Complexity to go down and the Maintainability to go up.

imageFigure: Extracting 1 method out of Page_Load, “Maintainability Index” goes up - NICE

 

Extract til you drop, but with meaningful names!!!

Code smell - READIBILITY

In my opinion readability is the most important attribute of code.

Good code should be easy to read.
That makes code easy to understand, maintain and REUSE.

 

Ignore the meaning of the code but look at the layout... What would you prefer?

  if (myTrueValue) myFirstTempVariable = 1;
  if (!myTestStatement) mySecondTempVariable = 0;
  if (mySecondTestStatement) myThirdTempVariable = 0;
  if (!myFourthTestStatement) mySecondTempVariable = 1;
Hard to read

 

  if (myTrueValue == true) myFirstTempVariable = 1;
  if (myTestStatement == false) mySecondTempVariable = 0;
  if (mySecondTestStatement == true) myThirdTempVariable = 0;
  if (myFourthTestStatement == false) mySecondTempVariable = 1;
GOOD: Already much easier to read

 

  if (true == myTrueValue) myFirstTempVariable = 1;
  if (false == myTestStatement) mySecondTempVariable = 0;
  if (true == mySecondTestStatement) myThirdTempVariable = 0;
  if (false == myFourthTestStatement) mySecondTempVariable = 1;
GOOD: What about this? Already much easier to read??

Latest Posts

Popular Posts