Saturday, October 10, 2015

Being Agile

This is a bit complicated than it sounds. Agile is not a set of processes that one can blindly follow. Nobody practices Agile method. It's a way of thinking about software development.

Let's start with a more formal description called Agile Manifesto. Agile Manifesto is a collection of 4 values and 12 principles to guide us through the process of software development.

Rather than dumping everything here, I'll take you through the right resources to read about it. Here is the Manifesto for Agile Development and the Principles behind Agile Manifesto. To be agile, you need to put these values and principles into practice.

Agile Methods

Agile methods are processes that follows agile philosophy. They consists of individual practices like setting coding standards, using version control etc. Of course, these practices have been around for years. But agile refines the set of existing principles by handpicking those which are aligned to agile philosophy, discarding the rest and also by bringing in some new ideas.

Every team, project and situation is unique. You might want to create your own agile method by mixing together various agile practices. But, creating a brand new agile practice from scratch is a bad idea unless you have used agile development for a prolonged period of time. Always start with an existing, proven method and refine it in lieu of starting one from scratch.

- learnings from the Art of Agile Development

Friday, August 28, 2015

Tower of Hanoi

Tower of Hanoi is a recurrent mathematical problem. In recurrence, the solution to each problem depends on the solutions to smaller instances of the same problem.

I'd solved this problem a few years ago. But now, since we talk about functional programming, I decided to solve the problem using Elixir.

Read more about the problem statement here: Tower of Hanoi.

If you want to try it interactively, go here.

Here is my solution:

defmodule TowerOfHanoi do

  def move(1, source, destination, intermediate) do
    IO.puts ["Move ", source, " to ", destination]

  def move(no_of_disks, source, destination, intermediate) do
    move(no_of_disks - 1, source, intermediate, destination)
    IO.puts ["Move ", source, " to ", destination]
    move(no_of_disks - 1, intermediate, destination, source)


I'm updating my GitHub repository (yedhukrishnan/mathematics) with more math problems. Feel free to check them out to suggest improvements or to give comments.

Saturday, May 02, 2015

Functional Programming (Part 1)

I've been talking about Elixir for a while. It's never too late, but I believe it's high time to share what I learned about functional programming and why is it important.

Let's start with the fundamental difference. In an object oriented world, we solve the problem using classes and objects. A class depicts a behaviour while an object stores a state. While solving a problem, a lot of time is wasted modelling classes and hierarchies. But in a real world, we want to get things done than spending time maintaining states. This is what makes functional programming different. While the imperative style of programming concentrates on what and how to get things done, functional programming concentrates only on what. How is it being done, we don't need to worry about that.

In functional programming, we never mutate data. We just transform them. What's the big deal if we change some existing data? Here is the simplest explanation: We don't need to worry about data inconsistencies in a multi-threaded environment. It's always ensured that nobody is going to touch the data created by us.

Friday, April 17, 2015

Recursion (Part 1)

Unlike in imperative languages, functional programming languages (including Elixir) achieve looping through recursion. Why? To explain that, let's consider C:
for(i = 0; i < 5; i++) {
  sum = sum + i;
Here we are modifying (mutating) the value of i as well as sum in each interation. Mutation is considered as a bad practice and functional programming languages do not encourage it. Let's see some basic examples of recursion in Elixir.

Say, we want to print the message "hello" five times. How do we do that?
defmodule Recursion do
  def print_hello(n) when n <= 1 do
    IO.puts "hello"

  def print_hello(n) do
    IO.puts "hello"
    print_hello(n - 1)

Recursion.print_hello("Hello!", 3)
# Hello!
# Hello!
# Hello!
Here, defmodule is used to define a module (group of several functions). We can have multiple definitions of the same function. In the first function when n <= 1 is a guard. This function will get executed only when the guard condition is satisfied (no wonder why it is called a guard!). When there are multiple clauses (definitions) of the same function, Elixir looks for a match and executes it when it finds one. If no matches are found, it will throw error.

In this case, when n = 3 and n = 2, the second clause will be executed. When n = 1, the first clause will get executed. 

Read more:

Wednesday, April 15, 2015

Elixir Language (Part 5)


In the last section, we talked about representing strings as UTF-8 encoded binary. But we left a topic for this section: How a character having code point above 255 is represented in binary?

Well, we all know that a single byte can only hold a value between 0 and 255. Let's consider the string hełło. Here ł has a code point 322.

This is where UTF-8 comes into picture. It solves the problem by using 2 bytes to represent each ł, and one byte each to represent h, e and o.

iex> string = "hełło"
iex> byte_size string
iex> String.length string
Here, we can see that the byte size of the string is 7 while the string length is 5. The function byte_size/1 can be used to check how many bytes are actually used in the memory to represent the given string.

Read more: Binaries, strings and char lists

Sunday, December 28, 2014

Testing (Part 2)

In the previous post, we've looked at what to test. Now it's time to see how to test. There are several different aspects:

  • Regression Testing - Here, we test the result of current test with its previous results. This ensures that the bugs we fixed today didn't break the things that were working yesterday.
  • Test data - There are two types of test data: real world data and synthetic data. Both are important, because each of these tests different aspects and behaviour of the system.
  • Exercising GUI Systems - Testing GUI required special testing tools. Some of them record the events and play whenever required, while some others are based on a script. Writing code that is decoupled from GUI helps us to write better tests, because we can test the backend without interacting with the GUI.
  • Testing the Tests - How do we test the tests? The easiest way is to introduce bugs intentionally in the tests and see if they complain. 
  • Testing Thoroughly - How do we know if we have tested our code thoroughtly? The answer is we don't, and we never will. But we can use coverage analysis tools to keep track of it.

- summary of Ruthless Testing, from The Pragmatic Programmer: from Journeyman to Master 

Saturday, December 27, 2014

Testing (Part 1)

Generally, developers hate testing. They hate to see their code breaking.

But we don't. We test every bits and pieces in our code. Why? Because we know that this is one place where we can see Butterfly effect in action! One simple mistake can cause large (and very bad, of course) effects in the future.

Test Early, Test Often, Test Automatically

Many teams develop elaborate test plans for their project. But automated tests, which run with every build is far better and successful than test plans that sit on a shelf. The earlier we find the bug, the easier the fix. In fact, a good project may have more test code than production code.

Just writing tests is not enough. We have to make sure that we run that often. We cannot say that coding is done unless all the tests are passing. These are some major types of test we need to perform:
  • Unit Testing - Tests a module. Because if the module can't work alone, it cannot work with others as well.
  • Integration Testing - Tests how the subsystems play and interact with each other.
  • Validation and Verification - Ensures that what is build is what the user needs. Checks the functional requirements.
  • Resource Exhaustion, Errors and Recovery - Tests how the system behaves in real world conditions under varying factors like memory, CPU bandwidth etc.
  • Performance Testing - Stress testing, in which we tests our system and how it behaves when there is heavy load.
  • Usability Testing - Different from all the above tests. Here we test the system with real users. It helps us to know how easy it is for them to use it.

- summary of Ruthless Testing, from The Pragmatic Programmer: from Journeyman to Master