TDD: Clean Code That Works

Test Drive

Kaprekar Number

Kaprekar number is a non-negative integer, the representation of whose square can be split into two parts that add up to the original number.

 

Write a function that determines if a given number is a Kaprekar number or not.

Questions?

Predicted Questions

  • Can you explain what is Kaprekar number again, in an easily understandable language please?
  • Can you give me an example of its input?
  • What kind of output do you want me to print? Is it "true" or "false" value? Or is it "kaprekar" or "not kaprekar" value?

With No Tests

def kaprekar?(k)
  result = false
  power = k ** 2
  power_str = power.to_s
  for i in 0..(power_str.size - 1)
    num1 = power_str[0,i].to_i
    num2 = power_str[i,power_str.size-1].to_i
    if k == num1 + num2
      result = true
      break
    end
  end
  result
end

puts "Is kaprekar 9: #{kaprekar?(9)}"
puts "Is kaprekar 45: #{kaprekar?(45)}"
puts "Is kaprekar 7777: #{kaprekar?(7777)}"
puts "Is kaprekar -9: #{kaprekar?(-9)}"
puts "Is kaprekar 33: #{kaprekar?(33)}"

Self-Testing Code

What is Self-Testing Code?

  • Code that have built-in tests
  • which serve as a binding contract
  • and can be run arbitrarily

Install RSpec

source 'https://rubygems.org'

gem 'rspec'

Gemfile

bundle install

Execute command:

Change Directory Structure

.
├── Gemfile
├── Gemfile.lock
├── lib
│   └── kaprekar.rb
└── spec

Setup your directory structure to look like this:

Create Unit Tests

require "kaprekar"

describe 'Kaprekar' do
  it 'should return true when the input is 9 because 9 * 9 is 81 and 8 + 1 is 9' do
    expect(kaprekar?(9)).to eq(true)
  end

  it 'should return false when the input is 8 because 8 * 8 is 64 and 6 + 4 is not 8' do
    expect(kaprekar?(8)).to eq(false)
  end

  it 'should return false when the input is a negative integer' do
    expect(kaprekar?(-9)).to eq(false)
  end
end

spec/kaprekar_spec.rb

rspec -fd

Run:

The Parallels (1)

Remember the points in our questions earlier?

  • easily understandable
  • example input
  • expected output

The Parallels (2)

require "kaprekar"

describe 'Kaprekar' do
  it 'should return true when the input is 9 because 9 * 9 is 81 and 8 + 1 is 9' do
    expect(kaprekar?(9)).to eq(true)
  end

  it 'should return false when the input is 8 because 8 * 8 is 64 and 6 + 4 is not 8' do
    expect(kaprekar?(8)).to eq(false)
  end

  it 'should return false when the input is a negative integer' do
    expect(kaprekar?(-9)).to eq(false)
  end
end

easily understandable description

example input

expected output

Test Driven Development

The goal of test driven development is to produce clean code that works

- Ron Jeffries, founders of Extreme Programming

Steps

  • Write a test
  • Run the test and see it fails
  • Write just enough code to make it pass
  • Run the test and see it passes
  • Refactor
  • Run the test to ensure it still passes

FIRST Principle

  • Fast
  • Independent
  • Repeatable
  • Self-checking
  • Timely

But How? And Why?

Throughout the day, we are going to teach you how to write clean code that works while discovering why it matters.

Preparation

Non-Negotiable Ettiquette

  • Indentation and spacing between code constructs (classes/methods/specs) must be consistent
  • Use only spaces (no tabs) for indentation
  • Follow accepted naming conventions for Ruby
  • Follow accepted naming file and directory structure for Ruby
  • Use namespaces
  • No comments/unused code must ever be checked in
  • Use .gitignore
  • Ensure there is a README.md that includes
    • Problem Description
    • Dev environment setup
    • Build instructions
    • Run instructions
  • TDD (this should show in clear pattern in the commit log)

rm -rf

Failure to comply with non-negotiable etiquette will result in rm -rf to your code.

Group Responsibility

  • Ensure conventions
    • indentation and spaces
    • naming
    • file and directory structure
  • Write a script that automate project structure to follow the conventions

Problem Sets

Problem Set #1

As a fan of geometry,
I want to model a line based on points consisting of (x, y) co-ordinates using the cartesian system,
So that I can calculate its length.

Problem Set #2

As a fan of geometry,
I want to compare two lines for equality based on the end points,
So that I know when two lines are the equal.

Problem Set #3

As a fan of geometry,  
I want to model a rectangle with sides of lengths a and b,  
So that I can calculate its perimeter.

Lessons Learned

Concepts

  • Express intent
  • Simple English modeling
  • Baby steps
  • YAGNI
  • DRY
  • KISS
  • SRP
    • Job of class
    • Tell, don't ask
    • Law of Demeter

Clean code is not written by following a set of rules. You don’t become a software craftsman by learning a list of heuristics. Professionalism and craftsmanship come from values that drive disciplines.

- Robert C. Martin, author of Clean Code

TDD: Clean Code That Works

By qblfrb

TDD: Clean Code That Works

  • 419