Documentation over tests

I’d rather have documentation than tests. Here’s a concrete example of a horrible documentation fail. Take a look at the configuration example:


    ...
    
        cross-origin
        org.eclipse.jetty.servlets.CrossOriginFilter
    
    
        cross-origin
        /cometd/*
    
    ...

Are you kidding me? Dot Dot Dot?? What other configuration options are there? Using googlefu you come across questions like this. The poster in this case has no idea that for example allowedMethods and allowedHeaders cannot have * as a value… Because the documentation said so? No, because as we see the documentation doesn’t even include these options as configuration value … Unless you know what the prior punctuation somehow magically means.

So after looking up the code. I know what a valid configuration document should look like. What’s wrong with that picture, SOLID people?

For a cross origin pre-flight request in jetty, you have to specify the headers to include … And … Then … You also have … to … specify … the … actual … HTTP … Verbs … That … You’ll … Apply …


   		cross-origin
   		org.eclipse.jetty.servlets.CrossOriginFilter
   		
allowedOrigins
*
   		
   		
allowedMethods
GET,POST,HEAD,PUT,DELETE
   		
		
allowedHeaders
X-Requested-With,Content-Type,Accept,Origin,x-custom-header
		
 	

Give me documentation, or give me death. – Patrick Henry

Scramble your facebook posts for privacy

I’m working on scrambls.com. A tool that allows you to manage who exactly can see your posts. How? Well if you were my real friend, you could see this message below:

[scrambls}ceitzVj2Q ☎⋝ ≉≋≩☍ ∽☊≖☇⊤⋓⊶ ⊑⋩≜ ≡⊼≇ ⋃∍⊲ ☈⊓∁⊙∧≮∭⊫⊂{]

If you think it’s neat just comment on facebook and I’ll send you an invite to get started :)

Parsnips

Validate Comma Separated Email Jquery Validation Engine

Another quick tip, utilizing underscore and validation engine

function validateEmail(field, rules, i, options) {
   if (!_.all(field.val().split(","),
      function(candidate) {
         return $.trim(candidate).match(options.allrules.email.regex);
      })
   ) return options.allrules.email.alertText;
}

haproxy http to https redirect

For those who are lazy, and don’t want to understand haproxy thaaat well. In order to redirect all traffic from http to https use a variation of the following in your haproxy.cfg

#---------------------------------------------------------------------
# Redirect to secured
#---------------------------------------------------------------------
frontend unsecured *:80
    redirect location https://foo.bar.com

#---------------------------------------------------------------------
# frontend secured
#---------------------------------------------------------------------
frontend  secured *:443
   mode  tcp
   default_backend		app

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
    mode  tcp
    balance roundrobin
    server  app1 127.0.0.1:5001 check
    server  app2 127.0.0.1:5002 check
    server  app3 127.0.0.1:5003 check
    server  app4 127.0.0.1:5004 check

Create Ranges of Numbers with SQL

So in yesterdays post, the “monthly” requirement was going to be a challenge. Let’s remind ourselves of what the requirement is:

3. “Monthly” = This will be 0-30, 31-60, 61-90, 91-120, 121-150, 151-180, etc

The problem is, I don’t know how many of those groupings can exist. To solve this, I went into the bag of tricks and pulled out some recursion.

--SETS up aging bands in 30 day increments.
-- 0-30, 31-60, 61-90 until all inventory is accounted for.

CREATE TABLE #TempAgingBands (
AgingBandId int identity(0,1),
Start_Value int,
End_Value int,
Label nvarchar(20)
)

CREATE TABLE #TempAgingBandsEndValue (
AgingBandId int identity(0,1),
End_Value  int
)

declare @Today date
declare @DogDate date
declare @MaxDays int

-- Get two dates, today and say some time in 1900's to show whats up
set @TODAY = GETDATE()
set @DOGDATE = DATEADD(DAY, -40150, @Today)
set @MaxDays = DATEDIFF(day, @DogDate, @Today)  ;   

-- Use Recursion to generate a list of start values (1, 31, 61, 91 etc) *NOTE You'll see how we'll change 1 to 0 below*
WITH Nbrs ( n ) AS (
		SELECT 1 UNION ALL
		SELECT 30 + n FROM Nbrs WHERE n < @maxDays )
	INSERT INTO #TempAgingBands (Start_Value)
	SELECT n FROM Nbrs
	OPTION ( MAXRECURSION 32767 ) ;

-- Use recursion to generate list of end values (30, 60, 90, 120 etc)
WITH Nbrs ( n ) AS (
        SELECT 30 UNION ALL
        SELECT 30 + n FROM Nbrs WHERE n < @maxDays + 30 )
    INSERT INTO #TempAgingBandsEndValue(End_Value)
	SELECT n FROM Nbrs
    OPTION ( MAXRECURSION 32767 ) ;

-- Put start and end values in the aging band table.
UPDATE #TempAgingBands
SET #TempAgingBands.End_Value = t2.End_Value
FROM #TempAgingBandsEndValue t2
WHERE #TEmpAgingBands.AgingBandId = t2.AgingBandId

-- The first record is 1,30 it should be 0,30 so update it.
UPDATE #TempAgingBands
SET Start_Value = 0
WHERE AgingBandId = 0

-- Update to get appropriate list of labels.
UPDATE #TempAgingBands
SET Label = (convert(varchar(7),Start_Value) + ' - ' + convert(varchar(7),End_Value))

-- See the results. #winning
select * from #TempAgingBands

Is there a way to update #TempAgingBands without creating a second temp table?

SQL Trickery

Today I had the unenviable task of trying to change an existing report which grouped line items into “aging bands”,  to have multiple aging bands.    The requirement given was  this:

The Dog Report currently has only one choice of Aging Band, which reports inventory in as follows:

0-180
181-270
271-330
331-365
366-455
>455

We need to amend this Aging Band filter by offering 3 choices:
1. “Standard” = This will be the current aging bands above as presented in the attachment
2. “Bank” = This will be 0-180, 181- 270, 271-365, >365
3. “Monthly” = This will be 0-30, 31-60, 61-90, 91-120, 121-150, 151-180, etc

The previous implementation logic would tag each record with a grouping label based on how many days from today the record was indicating.  Additionally, records in the future (DogDate < 0) would be grouped with 0 – 180… Here’s the old logic:

CREATE TABLE #TempAgingBands (
AgingBandId int,
Start_Value int,
End_Value int,
Label nvarchar(20)
)

CREATE TABLE #TempDog (
OrderDogDays varchar(2),
DogDate date
)

-- Setup Aging Band table
INSERT INTO #TempAgingBands (AgingBandId, Start_Value, End_Value, Label)
VALUES ('0', 0, 180, '0 - 180'),
	   ('1', 181, 270, '181 - 270'),
	   ('2', 271, 330, '271 - 330'),
	   ('3', 331, 365, '331 - 365'),
	   ('4', 366, 455, '365 - 455'),
	   ('5', 455, -1, '> 455')

--Some records are inserted into #TempDog

UPDATE #TempDog
SET OrderDogDays = (CASE WHEN DATEDIFF(day, DogDate, @Today) <= 180
						THEN 0
					WHEN DATEDIFF(day, DogDate, @Today) > 180 AND DATEDIFF(day, DogDate, @Today) <= 270
						THEN 1
					WHEN DATEDIFF(day, DogDate, @Today) > 270 AND DATEDIFF(day, DogDate, @Today) <= 330
						THEN 2
					WHEN DATEDIFF(day, DogDate, @Today) > 330 AND DATEDIFF(day, DogDate, @Today) <= 365
						THEN 3
					WHEN DATEDIFF(day, DogDate, @Today) > 365 AND DATEDIFF(day, DogDate, @Today) <= 455
						THEN 4
					WHEN DATEDIFF(day, DogDate, @Today) > 455
						THEN 5
					END)

The original developer didn’t make use of his Start_Value and End_Value fields he defined… I wanted to use something more flexible to encapsulate any aging band definition they came up with… So here’s my try:

UPDATE #TempDog
SET OrderDogDays = (SELECT t.AgingBandId FROM #TempAgingBands t WHERE t.End_Value = -1 AND DATEDIFF(DAY, DogDate, @Today) > t.Start_Value
					UNION
					SELECT TOP 1 t.AgingBandId FROM #TempAgingBands t WHERE DATEDIFF(day, DogDate, @Today) >= t.Start_Value
								AND DATEDIFF(day, DogDate, @Today) <= t.End_Value
								AND t.End_Value != -1 AND DATEDIFF(day, DogDate, @Today) >= 0
					UNION
					SELECT top 1 0 FROM #TempAgingBands t WHERE DATEDIFF(day, DogDate, @Today) < 0)

Can you think of a better way to do the third union?

Invade Wall Street or Whatever … Dude

Have you heard of the “Occupy Wall Street” movement? If you listen to Glenn Beck, these are the so called social justice brigade that is going to incite violence in the street.

The massive social justice brigade

Since when did hipsters become a political force that we became scared of? Are they going to burn all their vinyl on the streets until the man forgives their student loans? I mean for Pete’s sake, they can’t even manage to shower in the morning, let alone start a “revolution”.

Catch the intellectual weight of some of their arguments. Such poised opinions can only come from someone who’s spent their whole life surfing Goodwill’s across America finding a plaid scarf to match his Guess glasses frames.

Hey 99 per-center, get a hair cut and a job. Dweeb.

Problem Solving Skills

Today I decided to take the code challenge of a startup full of really smart people doing a social networking site. They use interviewstreet.com for their code test, and I think it’s a really good way to get the riff raff out if you’re looking to hire someone who is really top notch.

You get 1 hour to complete the two interview questions. I managed to successfully complete one of the questions. I chalk up not completing the other question due to it being poorly written. It’s possible that I just can’t read too. I’ll break down my thought process in solving the problem I did successfully solve, and maybe you too can know how I think.

Here is the problem:

A 7-digit number consists of 7 distinct digits (from 0-9). The product of the first 3 digits = product of central 3 digits = product of last 3 digits. Find the middle digit

There’s a lot of cool math things going on in this problem:

  • Transitivity Property
  • 7 digit number, made up of unique digits -> Permutation
  • Even though the problem states 0 is part of the set of numbers, we can’t use it because 0 * any group of number is zero.

Ok, so knowing these characteristics of the problem, I set about a plan of attack:

  1. Find all permutations put them in a list.
  2. Iterate through list of permutations, use transitivity property to find answer
  3. ???
  4. profit

So I first set out to write a function to find all the permutations. How big of a problem is that?

P = n! / (n – k)!

With our problem set that’s 181,440 possibilities. Ok, so I gotta write an efficient program to do that…

My head started hurting, surely there’s a library that will help? Yes? Ok, python has itertools.permutations()… don’t re-invent the wheel… So here’s the final code:

import itertools

permutations = itertools.permutations([1,2,3,4,5,6,7,8,9],7)

for candidate in permutations:
    val = candidate[0] * candidate[1] * candidate[2]
    if val == candidate[2] * candidate[3] * candidate[4]:
        if val == candidate[4] * candidate[5] * candidate[6]:
            print candidate[3]
            break

And the answer is 2. Cheers.

What prevents problems from being solved?

This is a question that I’ve pondered for a long time.

Take this one:

http://stackoverflow.com/questions/1610874/snireadsync-executing-between-120-500-ms-for-a-simple-query-what-do-i-look-for

Asked in October of 2009, our team was finally able to put this problem to rest, and more importantly improve site performance, database scalability and application cpu levels in a significant way. It took over a year to achieve, what essentially is a 3 line change in application server code and database configuration. So my question is, why did it take this long?

In order to answer this question, I think there are three categories of answer that are possible:

1. We didn’t know how to solve it.
2. We didn’t care to solve it.
3. We didn’t know to care to solve it.

So which was it?

#1. We ended up solving the problem. We researched several alternatives and came up with a solution. This work in aggregate took about a “man week”. By definition, this couldn’t have been the cause of the delay.

#2. We did care to solve it. I was perplexed by the issue a year ago. However, I didn’t have the experience/knowledge/data to raise the profile of the problem to something that should take priority.

#3. I think this is the winner. Until Seamlessweb purchased Dynatrace (which is awesome by the way), there was no way to reliably analyse the data and make a solid prediction which could be sold the business as a valuable proposition. But it wasn’t just a tool which told us, essentially what we already knew. It was an organizational change which gave ownership of the technology platform, and in effect recognizing there was a problem to begin with. Once the business stake holders recognized that being concerned specifically with the technology platform as a whole, gave us the opportunity to sell the right solution to them at the right time.

The real value out of all this is to try and remember how we achieved this. Right now, all I remember is a lot of painful waiting. But maybe that’s the proof of the adage all good things are worth waiting for.

The worst trade ever


“Banner Day”
is the title of ESPN.com’s coverage of the Magic acquiring Gilbert Arenas, Hedo Turkgolu, Jason Richardson and Earl Clark.   What should the title be?  ”Phoenix Redeems Marion for Shaq trade”.  Let’s break it down:

Phoenix needs size and to cut salary.

Orlando needs front court depth, and a pass first point guard.

Washington needs another spot up shooter and size.

What did each team get?

Phoenix:

  • Replaced their slashing athletic scorer for another slightly older athletic slashing scorer (JRich for VC)
  • Got a decent center who can grab rebounds and guard Gasol or Bynum (Gortat)
  • Got another perimeter defender who can shoot the 3 ball and help guard Kobe (Pietrus)
  • Turned a big contract into a big expiring contract (JRich for VC)
  • Got a first round draft pick
  • Cut this years salary by dumping Hedo Turkgolu
  • Dumped Hedo Turkgolu

Washington:

Got rid of their ball hog point guard and replaced him with a big that can shoot and create his own shot if need be.

Orlando:

  • Got worse on defense
  • Got rid of their only guy who can stay in front of Lebron (Pietrus)
  • Got rid of best backup center in NBA (Sorry Joel Pryzbilla)
  • Added another shoot first pass never point guard
  • Added Jason Richardson, who will never get passed to since Agent 0 and Jameer Nelson will be too busy taking bad shots.
  • “Added” Hedo Turkgolu.

Otis Smith should immediately be fired.