Problem Solving Techniques
For Evolutionary Design
Distilling Down Any Problem to Its Crux
Naresh Jain
naresh@xnsio.com
@nashjain
https://xnsio.com
Rounding Up to the
Closest 5 Cents
• In my billing application
• Given the price of an item comes up to $20.23
after tax
• I want to round up 23 cents to the closest 5
cents denomination .i.e. 25 cents
• So I can charge $20.25
• https://github.com/nashjain/rounding_logic
• https://help.github.com/categories/54/articles
Tests
@Test
public void shouldLeaveAsIsIfAlreadyInDenominationsOf5Cents() {
assertEquals(20.25, round(20.25), 0.01);
}
@Test
public void shouldRoundUpToNext5Cents() {
assertEquals(20.25, round(20.24), 0.01);
}
@Test
public void shouldRoundUpEvenIfAmountIsLessThanPoint023() {
assertEquals(20.25, round(20.21), 0.01);
}
https://github.com/nashjain/rounding_logic
Rounding Up - Answer
• var price = 20.23;
• var rounded_price = ceil(price / 0.05) * 0.05;
or
• var rounded_price = ceil(price * 20) / 20;
Hotel Room Charge
• Calculate the bill amount based on the number of hotel nights
the guest has stayed in the hotel.
• Per hotel night is charged at 4999 INR for single occupancy and
5499 INR for double occupancy.
• Hotels have a standard 12:00 noon checkin and checkout.
• Early Checkin: Guest can request to checkin early (before
12:00 noon.) If they checkin between 9 and 12, they are
charged 50% extra. If they checkin before 9 AM, then they are
charged full night charge.
• Late Checkout: Guest can request a late checkout. If they
checkout after 12 noon and before 3, they are charged 50%
extra and if they checkout after 3:00 PM, they have to pay one
whole night's extra charge.
function calculate_hotel_charge(occupancy, hotel_checkin, hotel_checkout) {
var per_night_rate = occupancy == ‘Single’ ? 4999 : 5499;
return per_night_rate * total_nights(hotel_checkin, hotel_checkout);
}
function total_nights(hotel_checkin, hotel_checkout) {
return max(actual_nights(hotel_checkin, hotel_checkout)
+ early_checkin_nights(hotel_checkin)
+ late_checkout_nights(hotel_checkout), 1);
}
function actual_nights(hotel_checkin, hotel_checkout) {
return floor((hotel_checkout - hotel_checkin) / (24 * 60 * 60 * 1000));
}
functional early_checkin_nights(hotel_checkin) {
if(hotel_checkin.getHours() > 12) return 0;
if(hotel_checkin.getHours() > 9) return 0.5;
return 1;
}
Hotel Room Charge Solution
functional late_checkout_nights(hotel_checkout) {
if(hotel_checkin.getHours() < 12) return 0;
if(hotel_checkin.getHours() < 3) return 0.5;
return 1;
}
High-level Approach
Eliminate Noise Divide & Conquer
Test Data
Constraints Simple Design
Manual Debug
Refactor
Throw Away
Create
Add
Come
up with
Simplify the Problem
Prioritise
Remove
constrains
Works?
More Constraints Exit?
Yes
No
Problem-Solving Strategies
• Sandboxing: solving the problem in a model of the system before
applying it to the real system
• Metaphor: using a solution that solves an analogous problem
• Brainstorming: exploring a large number of solutions or ideas
and combining and developing them until an optimum solution is
found
• Divide and conquer: breaking down a large, complex problem
into smaller, solvable problems
• Hypothesis testing: assuming a possible explanation to the
problem and trying to prove (or disprove) the assumption
• Reduction: transforming the problem into another problem for
which solutions exist
• Trial-and-error: testing possible solutions until the right one’s
Adapted from: http://en.wikipedia.org/wiki/Problem_solving#Problem-solving_strategies
Commercial Break!
Copyright ©
2012,
Mumbai
Tech Talks!
IP Address Range
• Each country has blocks of IPv4 address
range assigned to it
• Given I have an IP address I want to figure
out which country it belong to
Start End Total IPs Country
1.6.0.0 1.7.255.255 131072 India
1.22.0.0 1.23.255.255 131072 India
1.186.0.0 1.186.255.255 65536 India
1.0.32.0 1.0.63.255 8192 China
1.1.16.0 1.1.31.255 4096 China
1.4.16.0 1.4.31.255 4096 Japan
• https://github.com/nashjain/ip2country
• 196 countries with 100s of such blocks
public long convertToNumericIp(String ip) {
long numericIp = 0;
String[] octets = ip.split(“.");
for (int i = 0; i < 4; ++i)
numericIp += parseInt(octets[i]) * Math.pow(256, 3 - i);
return numericIp;
}
243.131.122.231
243*256*256*256 + 131*256*256 + 122*256 + 231
= 4085480167
Snakes and Ladders
• One or more players can play the game
• Typical board size is 10 x10, but user can specify
different board size
• User can decide the game mode (Easy = 5 snakes and
ladders, Medium = 10 snakes and ladders, Hard = 20
snakes and ladders.) Default to easy mode.
• After each move, snakes and ladders could move, but
at least after each game, they should move.
• Game takes the names of all the players and reports
the name of the winner.
• Random player gets to start
def move(players, player_turn)
new_position = players[player_turn] + throw_dice
new_position = @snakes_ladders[new_position]
if @snakes_ladders.has_key?(new_position)
return player_turn if new_position >= @board_size
players[player_turn] = new_position
next_player = (player_turn + 1) % players.length
move(players, next_player)
end
https://github.com/nashjain/snakes_n_ladders
Medical Age Printer
Age Reported in
Greater than 1Year <Patient Name> is #Years old
> 1 Month & < 1Year <Patient Name> is # Months old
> 1 Day & < 1 Month <Patient Name> is # Days old
> 1 Hr & < 1 Day <Patient Name> is # Hours old
Doctors and Nurses might like to add and remove new Durations.
For Ex: If they add Decade, and Patient’s age is greater than 10 years,
then age should be reported as <Patient Name> is # Decades old.
Similarly: If they add Week, and Patient’s age is greater than 7 Day, but less than
a month, then age should be reported as <Patient Name> is # Weeks old.
https://github.com/nashjain/map
private static final long MILLIS_IN_MIN = 60 * 1000L;
private static final long MILLIS_IN_HOUR = MILLIS_IN_MIN * 60;
private static final long MILLIS_IN_DAY = MILLIS_IN_HOUR * 24;
private static final long MILLIS_IN_MONTH = MILLIS_IN_DAY * 30;
private static final long MILLIS_IN_YEAR = MILLIS_IN_DAY * 365;
private final TreeMap<Long, String> millisPerUnit = new TreeMap<Long, String>() {
{
put(MILLIS_IN_HOUR, "Hours");
put(MILLIS_IN_DAY, "Days");
put(MILLIS_IN_MONTH, "Months");
put(MILLIS_IN_YEAR, "Year");
}
};
public String since(Date dob) {
long deltaInMillis = differenceInMillisFromNow(dob);
Entry<Long, String> duration = millisPerUnit.floorEntry(deltaInMillis);
if (duration == null)
return "0 Hours";
return deltaInMillis / duration.getKey() + " " + duration.getValue();
}
private long differenceInMillisFromNow(Date date) {
return clock.now() - date.getTime();
}
Recap
Eliminate Noise Divide & Conquer
Test Data
Constraints Simple Design
Manual Debug
Refactor
Throw Away
Create
Add
Come
up with
Simplify the Problem
Prioritise
Remove
constrains
Works?
More Constraints Exit?
Yes
No
Important Advice
Pick a Solution after Trying
at least 3 Approaches
"Perfection (in design) is achieved not when there is nothing more to add,
but rather when there is nothing more to take away." – Eric S Raymond
Quit Multitasking
Deliberate Practice
Next Steps?
Practice An Hour Each Day
Participate
ThankYou!
Questions?
Naresh Jain
@nashjain
https://xnsio.com

Problem Solving Techniques For Evolutionary Design

  • 1.
    Problem Solving Techniques ForEvolutionary Design Distilling Down Any Problem to Its Crux Naresh Jain naresh@xnsio.com @nashjain https://xnsio.com
  • 2.
    Rounding Up tothe Closest 5 Cents • In my billing application • Given the price of an item comes up to $20.23 after tax • I want to round up 23 cents to the closest 5 cents denomination .i.e. 25 cents • So I can charge $20.25 • https://github.com/nashjain/rounding_logic • https://help.github.com/categories/54/articles
  • 3.
    Tests @Test public void shouldLeaveAsIsIfAlreadyInDenominationsOf5Cents(){ assertEquals(20.25, round(20.25), 0.01); } @Test public void shouldRoundUpToNext5Cents() { assertEquals(20.25, round(20.24), 0.01); } @Test public void shouldRoundUpEvenIfAmountIsLessThanPoint023() { assertEquals(20.25, round(20.21), 0.01); } https://github.com/nashjain/rounding_logic
  • 4.
    Rounding Up -Answer • var price = 20.23; • var rounded_price = ceil(price / 0.05) * 0.05; or • var rounded_price = ceil(price * 20) / 20;
  • 5.
    Hotel Room Charge •Calculate the bill amount based on the number of hotel nights the guest has stayed in the hotel. • Per hotel night is charged at 4999 INR for single occupancy and 5499 INR for double occupancy. • Hotels have a standard 12:00 noon checkin and checkout. • Early Checkin: Guest can request to checkin early (before 12:00 noon.) If they checkin between 9 and 12, they are charged 50% extra. If they checkin before 9 AM, then they are charged full night charge. • Late Checkout: Guest can request a late checkout. If they checkout after 12 noon and before 3, they are charged 50% extra and if they checkout after 3:00 PM, they have to pay one whole night's extra charge.
  • 6.
    function calculate_hotel_charge(occupancy, hotel_checkin,hotel_checkout) { var per_night_rate = occupancy == ‘Single’ ? 4999 : 5499; return per_night_rate * total_nights(hotel_checkin, hotel_checkout); } function total_nights(hotel_checkin, hotel_checkout) { return max(actual_nights(hotel_checkin, hotel_checkout) + early_checkin_nights(hotel_checkin) + late_checkout_nights(hotel_checkout), 1); } function actual_nights(hotel_checkin, hotel_checkout) { return floor((hotel_checkout - hotel_checkin) / (24 * 60 * 60 * 1000)); } functional early_checkin_nights(hotel_checkin) { if(hotel_checkin.getHours() > 12) return 0; if(hotel_checkin.getHours() > 9) return 0.5; return 1; } Hotel Room Charge Solution functional late_checkout_nights(hotel_checkout) { if(hotel_checkin.getHours() < 12) return 0; if(hotel_checkin.getHours() < 3) return 0.5; return 1; }
  • 7.
    High-level Approach Eliminate NoiseDivide & Conquer Test Data Constraints Simple Design Manual Debug Refactor Throw Away Create Add Come up with Simplify the Problem Prioritise Remove constrains Works? More Constraints Exit? Yes No
  • 8.
    Problem-Solving Strategies • Sandboxing:solving the problem in a model of the system before applying it to the real system • Metaphor: using a solution that solves an analogous problem • Brainstorming: exploring a large number of solutions or ideas and combining and developing them until an optimum solution is found • Divide and conquer: breaking down a large, complex problem into smaller, solvable problems • Hypothesis testing: assuming a possible explanation to the problem and trying to prove (or disprove) the assumption • Reduction: transforming the problem into another problem for which solutions exist • Trial-and-error: testing possible solutions until the right one’s Adapted from: http://en.wikipedia.org/wiki/Problem_solving#Problem-solving_strategies
  • 9.
  • 10.
  • 11.
  • 17.
  • 23.
    IP Address Range •Each country has blocks of IPv4 address range assigned to it • Given I have an IP address I want to figure out which country it belong to
  • 24.
    Start End TotalIPs Country 1.6.0.0 1.7.255.255 131072 India 1.22.0.0 1.23.255.255 131072 India 1.186.0.0 1.186.255.255 65536 India 1.0.32.0 1.0.63.255 8192 China 1.1.16.0 1.1.31.255 4096 China 1.4.16.0 1.4.31.255 4096 Japan • https://github.com/nashjain/ip2country • 196 countries with 100s of such blocks
  • 25.
    public long convertToNumericIp(Stringip) { long numericIp = 0; String[] octets = ip.split(“."); for (int i = 0; i < 4; ++i) numericIp += parseInt(octets[i]) * Math.pow(256, 3 - i); return numericIp; } 243.131.122.231 243*256*256*256 + 131*256*256 + 122*256 + 231 = 4085480167
  • 27.
    Snakes and Ladders •One or more players can play the game • Typical board size is 10 x10, but user can specify different board size • User can decide the game mode (Easy = 5 snakes and ladders, Medium = 10 snakes and ladders, Hard = 20 snakes and ladders.) Default to easy mode. • After each move, snakes and ladders could move, but at least after each game, they should move. • Game takes the names of all the players and reports the name of the winner. • Random player gets to start
  • 28.
    def move(players, player_turn) new_position= players[player_turn] + throw_dice new_position = @snakes_ladders[new_position] if @snakes_ladders.has_key?(new_position) return player_turn if new_position >= @board_size players[player_turn] = new_position next_player = (player_turn + 1) % players.length move(players, next_player) end https://github.com/nashjain/snakes_n_ladders
  • 29.
    Medical Age Printer AgeReported in Greater than 1Year <Patient Name> is #Years old > 1 Month & < 1Year <Patient Name> is # Months old > 1 Day & < 1 Month <Patient Name> is # Days old > 1 Hr & < 1 Day <Patient Name> is # Hours old Doctors and Nurses might like to add and remove new Durations. For Ex: If they add Decade, and Patient’s age is greater than 10 years, then age should be reported as <Patient Name> is # Decades old. Similarly: If they add Week, and Patient’s age is greater than 7 Day, but less than a month, then age should be reported as <Patient Name> is # Weeks old. https://github.com/nashjain/map
  • 30.
    private static finallong MILLIS_IN_MIN = 60 * 1000L; private static final long MILLIS_IN_HOUR = MILLIS_IN_MIN * 60; private static final long MILLIS_IN_DAY = MILLIS_IN_HOUR * 24; private static final long MILLIS_IN_MONTH = MILLIS_IN_DAY * 30; private static final long MILLIS_IN_YEAR = MILLIS_IN_DAY * 365; private final TreeMap<Long, String> millisPerUnit = new TreeMap<Long, String>() { { put(MILLIS_IN_HOUR, "Hours"); put(MILLIS_IN_DAY, "Days"); put(MILLIS_IN_MONTH, "Months"); put(MILLIS_IN_YEAR, "Year"); } }; public String since(Date dob) { long deltaInMillis = differenceInMillisFromNow(dob); Entry<Long, String> duration = millisPerUnit.floorEntry(deltaInMillis); if (duration == null) return "0 Hours"; return deltaInMillis / duration.getKey() + " " + duration.getValue(); } private long differenceInMillisFromNow(Date date) { return clock.now() - date.getTime(); }
  • 31.
    Recap Eliminate Noise Divide& Conquer Test Data Constraints Simple Design Manual Debug Refactor Throw Away Create Add Come up with Simplify the Problem Prioritise Remove constrains Works? More Constraints Exit? Yes No
  • 32.
  • 33.
    Pick a Solutionafter Trying at least 3 Approaches
  • 34.
    "Perfection (in design)is achieved not when there is nothing more to add, but rather when there is nothing more to take away." – Eric S Raymond
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.