Saturday, September 9, 2017

Keep design simple - don't design ahead

Keep the design as simple as possible.

Your current design should only support your current features. 

The problem is when we start looking ahead at all of the features as a whole, and then try to create some grand architecture in order to support all of the features.

You know what WILL happen? The design will be overkill, will be wrong, and it'll be fragile. It may work for feature #1, but once you start on feature #2, the design does not support it all. 

I've seen this happen over and over and over.

Wouldn't it make more sense to do the following?
  1. Design and code feature #1 using the simplest design possible
  2. Add unit tests
  3. Design feature #2 based on the current design. This may require refactoring the existing design to support feature #2. Keep it as simple as possible.
  4. Add unit tests
  5. Rinse and repeat all the way until the end
At the end you have the simplest design possible that currently supports all of the features. Since your code is always backed by unit tests, you can safely refactor. The design has grown exactly as needed. It's a bottom-up design. 
Note: Evolution is a bottom-up design process. 


When you design ahead, you're doing top-down design. And it typically looks like this:
  1.  Look at all features and come up with a design that seems to support all the features
  2. Code feature #1
  3. Code feature #2 - oh, the requirements for this changed. I'll need to refactor the framework a little bit to force it to handle feature #2
  4. Code feature #3 - oh, now that i'm coding this, i realize that the current design won't exactly support this. I'll just tack on this little thing and it'll work.
  5. Rinse and repeat for hundreds of features
At the end you have a top-down design that was changed many times due to bottom-up forces. The result is a kludgey mess that no one can make sense out of.

Since requirements always change, and because you don't know everything about every feature until you really start to work on that feature, there will always be bottom-up forces on the design. If the design has been kept as simple as possible every step of the way, then the bottom-up forces can be absorbed painlessly, and the design can gradually evolve. 





Sunday, August 20, 2017

Reading time calculation

Problem: I want to figure out how much reading i need to do in order to finish a book within a certain number of days

Solution
1. Go here and find out how long it'll take based on your WPM: http://www.readinglength.com


2.  Run this python script and update the parameters
There's two different approaches:

  • Process-oriented: I want to spend X minutes per day on this task 
  • Results-oriented: Regardless of how long i spend on this task, i want to accomplish X per day
In this case the results-oriented approach probably makes more sense. I could spend 30 mins reading a book, but due to distractions I could only read 5 pages. So process-oriented is not a good approach to this since the end result is that I need to have X number of pages completed in Y days.

Ref: run Python online here https://repl.it/languages/python3

Friday, August 11, 2017

Mocking static methods

Problem: How can I mock static methods in unit tests?


Solution
There are two cases:
  1. The static method is in a class that I can change
  2. The static method is in a class that I CANNOT change



Case 1 - Static Method is in a class that I can change


//Code Under Test
public class Foo { public static void Log(string msg) { System.IO.File.WriteAllText("log.txt", msg); } public bool Bar() { Log("Bar was called"); return true; } }

Solution - change method to a delegate, and then set it in the unit test to do nothing

1. Change Log method to a delegate

public class Foo { public static Action<string> Log = (msg) => { System.IO.File.WriteAllText("log.txt", msg); }; public bool Bar() { Log("Bar was called"); return true; } }

2. In the unit test do this
[TestMethod()] public void BarTest() { //Arrange Foo foo = new Foo(); Foo.Log = (msg) => { }; // a function that does nothing bool result = false; //Act result = foo.Bar(); //Assert Assert.IsTrue(result); }


Case 2 - Static Method is in a class that I cannot change

//The Logger class is in some library that I cannot change
    public static class Logger
    {
        public static void Log(string msg)
        {
            System.IO.File.WriteAllText("log.txt", msg);
        }
    }

//Code under test
    public class Foo
    {
        public bool Bar()
        {
            Logger.Log("Bar was called");
            return true;
        }
    }

Solution - wrap call to static method in a virtual method, then mock the wrapper to do nothing

1. Wrap call to static method in a virtual method, change code to call the wrapper

//Code under test
     public class Foo
    {
        public virtual void Log(string msg)
        {
            Logger.Log(msg);
        }
        public bool Bar()
        {
            Log("Bar was called");
            return true;
        }
    }

2. Mock the wrapper so it doesn't do anything
//Note: This is using Moq (https://github.com/Moq/moq4/wiki/Quickstart)

        [TestMethod()]
        public void BarTest()
        {
            //Arrange
            Moq.Mock<Foo> foo = new Moq.Mock<Foo>();
            bool result = false;

            //Act
            result = foo.Object.Bar();

            //Assert
            Assert.IsTrue(result);
        }

//Since Log() is void, and because there are no other virtual methods in the Foo class, i don't need to actually use the Moq Setup() method here.









Saturday, July 15, 2017

Recommended design-level books

I was recently asked which design books i would recommend. So here's design books that I've read and would personally recommend.
  1. Refactoring

Refactoring skills consist of these parts:
  1. Being able to spot code and design "smells". 
  2. Being able to systematically refactor smelly code to a better structure

Refactoring: Improving the Design of Existing Code

I use this site as a reference. When I do code reviews I send links to specific refactoring and code smells. 


2. Design Patterns

This book teaches the SOLID object-oriented design principles + design patterns. 

For example: 
1. The D in SOLID = Dependency-Inversion Principle
2. One design pattern is called the Observer Pattern. One thing this pattern used for is to invert dependencies. 

3. Making existing code unit testable

This book is basically about techniques to make existing code unit testable. The side effect of making code testable is that it has a good, loosely coupled design. 

Working Effectively with Legacy Code

4. Agile Principles, Patterns, and Practices

This book explains everything having to do with Agile. There are parts about the process, but more importantly it explains what we can apply as individual developers. Things like design principles (SOLID), patterns, refactoring, and test-driven development, and much more. 

Agile Principles, Patterns, and Practices in C# (there's a Java version too i think)

Tuesday, June 6, 2017

Get Kindle book highlights

I like to take all my highlights after reading a book and organize them into main ideas etc... One problem is they don't offer the ability to export the highlights without added junk.

How to get the highlights and clean them
1. Go to https://read.amazon.com/kp/notebook

2. Click on a book

3. Copy and paste the highlights to Notepad++ (download if you dont have it)

4. Do a Replace All using the regex: (Blue|Yellow) highlight \| (Location|Page): [0-9,]+\r\n

Add more colors to the first group if you use other highlight colors



Poof, all the junk is gone leaving just my highlighted text and notes!

Saturday, June 3, 2017

Starting VS debugger when you can't attach to process

Problem
I have a VB6 program that uses my .NET DLL. In an initializing function (before the UI is shown) a problem is happening that I need to debug by stepping into the .NET code. This is made difficult though, because i cannot Attach to Process 

Solution
Use System.Diagnostics.Debugger.Launch in the .NET code. When I use this, i no longer need to try to use Attach to Process

Saturday, May 20, 2017

Assembly.LoadFrom does not load types within a DLL

Problem
I'm using Assembly.LoadFrom to load an assembly during runtime and it's not able to load all of the types.

A useful symptom is that RequestingAssembly (in Resolve event) is null.

Solution
DLL names cannot match the containing folder.

For example, if I am trying to load ../Project/MyDLL/MyDLL.dll, it'll fail, simply because "MyDLL" is both the DLL name and folder name. The solution is therefore to put MyDLL.dll in a differently named folder.

Yes, this makes no sense, but I am not concerned about the internal workings of Assembly.LoadFrom(). After many hours of being confused, I finally found the solution here: http://stackoverflow.com/a/10245012/1538717 . I face-palmed so hard!

Saturday, April 22, 2017

Sunk Cost Fallacy in software development

I am working on a project having to do with government certification. One of their requirements is very odd, so we've had to put time an effort into doing design and research into how we could best meet the odd requirement. Given that this is for a government certification, the requirement is set in stone (or so we thought...!). We thought we simply misunderstood their requirement, and so we figured out two design alternatives - one that was simple based on what we thought they meant, and the other based on if they truly required this weird thing.

We got clarification and they truly required the weird thing. We accepted this, and spent 2 weeks on the design / proof of concept work that takes place before actual coding. That included review meetings with the top dogs in the company. So alot of time and effort was put into this design. 

The design was approved and the stars were aligning, code was about to be slapped into an IDE. But then at the last minute the government changed their requirement (weird, that never happens in software development!). They gave us a choice - we could do the weird requirement or the smart requirement, and we'd just need to tell them what way we chose. 

So now we're at a fork in the road:
  • Go ahead with the coding on the already-completed design, even though the road ahead was a long nasty one
  • Do the simple design approach, taking a day or two to go through the approval process again, and then proceed with the very simple coding

You'd think the obvious choice would be to do the simple design approach, but that's where the Sunk Cost Fallacy comes in. Time and energy was already spent on the first design, therefore we should continue to invest in this design! Nope. The time and energy spent on the WRONG design does not justify going forward with it. 

Sunk Cost Fallacy teaches us that the smart thing to do is cut our losses, and not be fooled into thinking that previous resources spent justifies continuing to throw resources at the wrong solution.

We did end up going with the simpler design, but that's because we were aware of the Sunk Cost trap, and were able to avoid it and make the wise decision.

Saturday, April 8, 2017

Operate on subsets of arrays using LINQ

LINQ Take() and Skip() make it easy to operate on subsets of an array, or any IEnumerable.

Sample problem: I want to know if a number is a contiguous sequence of digits in ascending order

       
Sample solution using Skip() and Take()
private static bool isAsc(int tester)
        {
          char[] asc = tester.ToString().Replace("0", ":").ToCharArray();
         
           char prev = asc[0];
           foreach(char c in asc.Skip(1))
           {
             prev++;
             if(prev != c)
              return false;
           }
           return true;
        }


if i didn't have Skip() available i would have written that like this:
for(int i = 1; i < asc.Length; i++)

Now, what if I wanted to find out if a subset had the property? Let's say, I want to know if the 2nd-5th digits have the property. In this case i would use Skip() + Take()

private static bool isAsc(int tester)
        {
          char[] asc = tester.ToString().Replace("0", ":").ToCharArray();
         
           char prev = asc[0];
           foreach(char c in asc.Skip(1).Take(3))
           {
             prev++;
             if(prev != c)
              return false;
           }
           return true;
        }


Ref:
1. Code Wars kata i used Skip() on: https://www.codewars.com/kata/52c4dd683bfd3b434c000292







Friday, March 24, 2017

Improve your code and design intuition

You should be able to develop your code and design sense to the point where you can look at anyone's code (including your own) and intuitively know if it's good or not. This is a critical skill to have if you are responsible for doing code and design reviews.

Here's some suggestions based on what i've done

1. Study design patterns and antipatterns
-Read some design patterns book. I liked Head First Design Patterns
-Read AntiPatterns
-Read Refactoring


2. Study good code, code smells, and refactoring
-Read Code Complete
-Read Clean Code
-Read Refactoring
-Read Programming Pearls

One of my favorite references for this is here: https://sourcemaking.com. I like to point to this in code reviews as a teaching tool. Like "use Extract Method for this part of the code. https://sourcemaking.com/refactoring/extract-method"

3. Lots and lots of practice

-Katas (links from Clean Coder book)
http://codekata.pragprog.com 
http://katas.softwarecraftsmanship.org
http://butunclebob.com/
http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html

-TopCoder algorithm challenges

-Code Wars

4. Use different languages and write different types of programs. Don't get too comfortable!
-Use C# at work? Study Python for fun
-Only do application development? Head to Udacity or freecodecamp for webdev

An excellent way to do this is to use 57 Exercises https://pragprog.com/book/bhwb/exercises-for-programmers




Saturday, February 4, 2017

Refactoring challenge - yahtzee

Refactoring challenge
http://jonjagger.blogspot.co.uk/2012/05/yahtzee-cyber-dojo-refactoring-in-java.html

My end results

                                           Original           Refactored
Maintainablility                  61                        90
Cyclometric Complexity    64                        47
Lines of Code                     157                      86

Class Coupling                    0                         11

My refactored C# version of this


using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RefactoringPractice { public enum DieValue { One =1, Two=2, Three=3, Four=4, Five=5, Six=6 } public class Dice { private static int NUM_DIE = 5; private int[] dice = new int[NUM_DIE]; private static DieValue[] dieValues = (DieValue[])Enum.GetValues(typeof(DieValue)); public Dice(int die1, int die2, int die3, int die4, int die5) { dice[0] = die1; dice[1] = die2; dice[2] = die3; dice[3] = die4; dice[4] = die5; } internal int Sum() { return dice.Sum(); } internal int SumOfNum(DieValue val) { return whereVal(val).Sum(); } private IEnumerable<int> whereVal(DieValue val) { return dice.Where(e => e == (int)val); } internal int CountOfNum(DieValue val) { return whereVal(val).Count(); } internal bool AllDieHaveNum(DieValue val) { return CountOfNum(val) == NUM_DIE; } internal static DieValue[] DieValues { get { return dieValues; } } } public static class Yatzy { public static int Chance(Dice dice) { return dice.Sum(); } public static int yatzy(Dice dice) { foreach(DieValue val in Dice.DieValues) { if (dice.AllDieHaveNum(val)) return 50; } return 0; } public static int Ones(Dice dice) { return dice.SumOfNum(DieValue.One); } public static int Twos(Dice dice) { return dice.SumOfNum(DieValue.Two); } public static int Threes(Dice dice) { return dice.SumOfNum(DieValue.Three); } public static int Fours(Dice dice) { return dice.SumOfNum(DieValue.Four); } public static int Fives(Dice dice) { return dice.SumOfNum(DieValue.Five); } public static int Sixes(Dice dice) { return dice.SumOfNum(DieValue.Six); } public static int ScorePair(Dice dice) { foreach(DieValue val in Dice.DieValues.Reverse()) { if (dice.CountOfNum(val) == 2) return (int)val * 2; } return 0; } public static int TwoPair(Dice dice) { int numPairs = 0; int score = 0; foreach(DieValue val in Dice.DieValues.Reverse()) { if(dice.CountOfNum(val) >= 2) { numPairs++; score += ((int)val * 2); } } if (numPairs == 2) return score; else return 0; } public static int FourOfAKind(Dice dice) { return OfAKind(4, dice); } private static int OfAKind(int num, Dice dice) { foreach (DieValue val in Dice.DieValues) { if (dice.CountOfNum(val) >= num) return (int)val * num; } return 0; } public static int ThreeOfAKind(Dice dice) { return OfAKind(3, dice); } private static int straight(int left, int right, Dice dice) { for (int i = left; i <= right; i++) { if (dice.CountOfNum(Dice.DieValues[i]) != 1) return 0; } return dice.Sum(); } public static int SmallStraight(Dice dice) { return straight(left: 0, right: Dice.DieValues.Length - 2, dice:dice); } public static int LargeStraight(Dice dice) { return straight(left: 1, right: Dice.DieValues.Length - 1, dice: dice); } public static int FullHouse(Dice dice) { foreach(DieValue threeKind in Dice.DieValues.Reverse()) { if(dice.CountOfNum(threeKind) == 3) { foreach(DieValue twoKind in Dice.DieValues.Reverse()) { if(dice.CountOfNum(twoKind) == 2) { return ((int)threeKind * 3) + ((int)twoKind * 2); } } } } return 0; } } }
There was an error in this gadget