Archive for December, 2014

Amazing Documentation Viewer – Dash

Friday, December 12th, 2014

Dash

I've been using Dash for a while now. It started out with a really odd looking cat as the icon, and it was a little iffy in the beginning, but it got better - a lot better. Today, it's the best documentation viewer I have ever used. It's just stunning. And it's fast. I can't believe how fast it is, but maybe it caches everything in a docket in memory - who knows? But Wow... it's easy to use, expansive on all the docs it covers, and the speed and ease of use are simply hard to beat.

I have a set for Clojure coding which includes clojure, postgres, and Java, and I have one set for ruby - with ruby, postgres and Java (for JRuby). All told, it's amazing how access to the right docs immediately is so powerful.

Recovery

Friday, December 12th, 2014

Path

I had a great phone call from an old friend last night. He's known me since the second grade. That's over 45 years. I don't have another friend that's even close to that long, and he's been a wonderful friend. He was remarking last night that he felt I was making progress, and that he was glad about that - and he should know... more than a decade as a nurse on the psych ward puts him in a position to know about recovery. So it was nice to hear that from him.

This morning I was looking at a pull request from one of the younger - and quite smart - developers in the group. I looked at what he'd done, and it was all just very sloppy. Basing the pull request off a deleted branch used in another pull request, and then not checking dependencies in the libraries, and then just changing things because he wanted to.

Typical kinds of things I've seen from a lot of smart, but not very disciplined, developers. They are used to their intelligence covering for their lack of attention to details and general discipline. Most of the time it works, but that's really just luck more than anything else. They aren't really compensating for it, they're just obscuring it. It's still there - the lack of detail, etc. and it'll come back to haunt the group and the code.

But I really can't say anything to him, because until he wants to change, he's not going to be receptive to any other person telling him he needs to change. We are all like that. I'm on a path now that I would have never voluntarily taken... in fact, I fought not to take it - but it had to be. Sooner or later, I had to realize that my marriage wasn't what I needed, nor was it what Liza needed, and maybe we shouldn't have been married, or maybe things just changed. Whatever the reason, it had to happen.

So it will be for the smart-but-lazy developer.

And at the same time, I've been told by many friends that the environment I've been in for months is not good for me. Again, I have been fighting that this should be a good fit, but that's based on a wish - not a fact. As I've interviewed with other shops, I've realized that I'm not a guy to be "just" a developer. That's going to be too big a mis-match, as I'm going to have decades of experience over my bosses, and that's only going to lead to issues.

Here again, I didn't want to see it - I just didn't want it to be true. But it was. I need to stop pretending that I'm happiest as just a developer. I'm a creative person, and consequently, I want to spend the majority of my time creating, but I can't shut off 30 years of professional programming, and all the mistakes made, and lessons learned. And when I am asked to make one of those mistakes again by a manager that hasn't yet made it, I really have to do it. But I can't. I just can't.

So I really need to be in the kinds of positions that I'm looking at currently - Senior Tech positions... Leads, Architects, decision maker. Something where my experience is a requirement so that it's not overlooked, but leveraged. I was again not thrilled with the idea of this a few months ago when I turned down promotions here at The Shop, but I see that was no different than me not wanting my marriage to end - wishful thinking, but sadly not accurate.

Yet I'm learning. Slowly, yes, but I'm learning. Accept. Forgive. Move on.

So I'm honestly looking forward to some of these opportunities I've interviewed for. There's a small company that needs someone to just help out. Lots of things to do, and because there aren't all that many people, there's lots to do. Then there's another place that's looking for real-time trading experience, and that's always a ton of fun to build - and the people there are smart and experienced so I'm not dealing with the 20-somethings that play cards during lunch and come in at 9:15.

Finally, there's one that might be the most interesting of all - as a tech lead for a line of business working side-by-side with the head of the business to make sure that the systems will scale, be robust, and keep moving in the right direction. This would require me to use everything I've learned and apply it on a daily basis - creatively and experientially.

Yet I know it's a path. I don't know that I'll ever have a day where I don't hurt about the marriage and family that might have been. Or the job or group that might have been. But those are just stories, and not reality. But the pain is very real.

My Favorite Muppet

Thursday, December 11th, 2014

Beaker

I was a big fan of The Muppet Show when I was younger... I never missed a Sunday night of that show. Such incredible memories... "Pigs in Space"... The Electric Mayhem... and of course - my favorite: Beaker. I could go on and on about why this character but it all comes down to the fact that he wanted so badly to belong, but at the same time he was always the victim - even if it was all accidental.

I don't know if this was the same for others, but I have to believe there was a genius in casting when they came up with Beaker and Dr. Bunsen Honeydew. But over and over again Henson came up with the perfect characters for each of us to identify with.

Anyway... listening to the Muppets Christmas album made me laugh at Beaker.

My Wonderful Siblings

Thursday, December 11th, 2014

I was scanning iPhoto this morning looking for the picture of the last family Christmas Tree I had, and I came across this picture that was taken of my family... my siblings and me. We have not always agreed with one another, but we have always been there for each other. Without question. Without hesitation. Without judgement.

My Siblings

I am blessed beyond words.

The Joy of Writing

Thursday, December 11th, 2014

smiley.jpg

I just updated my post about the conversion of the CryptoQuip Solver from Obj-C to ruby, and then for a piece of that to clojure, after having built that code in LightTable, and it just brought a smile to my face. The code was fun because closure allows me to do things that most languages simply don't, and it's always a simplification when that happens. In ruby I had to say:

  (pairs.count == ctc) && (ctc == ptc)

but in clojure, it's simpler:

  (= (count p) ctc ptc)

the = operator allows for any number of arguments - as does the other inequalities. Say I needed to have four numbers that all were ascending. That would be a hassle in ruby - maybe a sort, followed by the check that no two were the same, but in clojure it's as simple as:

  (< a b c d)

where it's only going to return true is d is greater than c is greater than b is greater than a. It's simple, and it's elegant.

But I also really like writing to friends about this stuff, and writing here as well. I've been recovering for almost two years now, and it's about time I work a little harder at just forgiving and moving on.

Because there's so much fun stuff to do, and if this little code block is all that exciting and fun to me, I've got a lot of fun ahead of me in a place that will feed my desire to solve problems.

And if I'm lucky enough to once again work for myself, then this blog is going to once again be open, and I'll be putting a lot more about solving problems up here as I think that's just amazingly fun stuff to share.

Christmas Day Plans Firming Up

Wednesday, December 10th, 2014

Christmas Tree

I was chatting with a friend today, and the movie Die Hard came up, and I realized that I haven't seen that moving in many years. Just as importantly, it was a really good movie. And the second one as well. So I was thinking... maybe I'll have a little Die Hard Christmas Film Festival? That might be nice.

So I looked at iTunes, and I can get the complete set of movies for $40. Not bad. I then looked at BestBuy and the Blu-Ray set is only like $27. I have no Blu-Ray player, but then I looked those up at BestBuy, and they aren't more than $60. Hey... we might have a winner here.

I've got my nice TV in the living room... and a $60 Blu-Ray player that does DVDs as well, and then the Die Hard set and for less than $100 I can have a really nice time on Christmas Day. I'm starting to look forward to this... Nice!

Ported the CryptoQuip Solver to Ruby

Wednesday, December 10th, 2014

Ruby

This morning I finished the little project I started yesterday on porting my old Obj-C CryptoQuip Solver from Obj-C to ruby. I wanted to brush up on my ruby skills as it's been nearly 18 months since I've done any real solid ruby development, and I've also wanted to get this codebase ported to Swift, and there are a lot of similarities between ruby and Swift. So this morning I finally got it all working as I wanted. Nothing really major, but I had made a few changes to try and capitalize on the strengths of ruby, and those made a few things that needed to be fixed up.

Nothing major.

But Wow... the codebase is significantly smaller. The original Obj-C code was well documented, and comes in at 3370 lines for all the headers and implementation files. Ruby is not as extensively documented, but it's a lot smaller so I didn't feel the need. It's a total of 316 lines. That's a factor of ten. Wow.

One of the nicest parts of the port was to change how I determined if a cyphertext word could potentially match a plaintext word. In the Obj-C code it looked like this:

  /*!
   One of the initial tests of a plaintext word is to see if the pattern of
   characters matches the cyphertext. If the pattern doesn't match, then the
   decoded text can't possibly match, either. This method will look at the
   pattern of characters in the cyphertext and compare it to the pattern in
   the argument and if they match, will return YES.
   */
  - (BOOL) matchesPattern:(NSString*)plaintext
  {
    BOOL   match = YES;
 
    // make sure that we have something to work with
    if (match && (([self getCypherText] == nil) || (plaintext == nil))) {
      match = NO;
    }
 
    // check the lengths - gotta be the same here for sure
    if (match && ([[self getCypherText] length] != [plaintext length])) {
      match = NO;
    }
 
    /*
     * Assume that each pair of characters is a new map, and then test that
     * mapping against all other cyphertext/plaintext pairs that SHOULD match
     * in the word. If we get a miss on any one of them, then we need to fail.
     */
    if (match) {
      unichar      cypher, plain, c, p;
      NSUInteger   len = [plaintext length];
      for (NSUInteger i = 0; (i < len) && match; ++i) {
        // get the next possible pair in the two words
        cypher = [[self getCypherText] characterAtIndex:i];
        plain = [plaintext characterAtIndex:i];
        // check all the remaining character pairs
        for (NSUInteger j = (i+1); (j < len) && match; ++j) {
          c = [[self getCypherText] characterAtIndex:j];
          p = [plaintext characterAtIndex:j];
          if (((cypher == c) && (plain != p)) ||
              ((cypher != c) && (plain == p))){
            match = NO;
            break;
          }
        }
      }
    }
 
    return match;
  }

where it's a pretty simple double-loop on the words. Nothing horribly hard here, but for ruby I went with a different idea to start with:

  # One of the initial tests of a plaintext word is to see if the pattern of
  # characters matches the cyphertext. If the pattern doesn't match, then the
  # decoded text can't possibly match, either. This method will look at the
  # pattern of characters in the cyphertext and compare it to the pattern in
  # the argument and if they match, will return true.
  def matches_pattern?(plaintext)
    return false unless @cyphertext && plaintext &&
                        @cyphertext.length == plaintext.length
    pairs = @cyphertext.chars.zip(plaintext.chars).uniq
    ctc = pairs.map { |p| p.first }.uniq.count
    ptc = pairs.map { |p| p.last }.uniq.count
    (pairs.count == ctc) && (ctc == ptc)
  end

I like the compactness of the ruby - very expressive, but the question is At what cost? The ruby version will check all the paris in the words, even if there is a mismatch in the second letter. This cost may - or may not - be a big deal. But it does simplify the code quite a bit.

The downside of the ruby implementation is that it's pretty slow. Where the Obj-C version was in the 60 msec range the ruby version (1.9.3 MRI) is more like 650 msec. This isn't a total shock, and I could have tried JRuby which will be considerably faster once the JIT gets warmed, but that wasn't the real point. It was just a fun little project to get this into ruby so that it might make it a little easier to get it into Swift.

And I got to brush up on my ruby too.

UPDATE: I tried it with JRuby 1.7.0, and yes, it's old, but it's a point of reference, and the times were worse. I did not expect that. The run times were in the 7 sec range. About an order of magnitude over the RMI version. Same code. Very odd, but I wanted to see what it'd be, and now I know.

UPDATE: I couldn't resist the urge to convert the new ruby scheme to clojure simply because I think clojure is going to be a lot more performant, and so I wanted to give that a try. The key pattern matching function is now:

  (defn matches?
    "Function to see if the cyphertext and plaintext have the same pattern of
    characters such that they could possibly match - given the right legend."
    [ct pt]
    (if (and (string? ct) (string? pt) (= (count ct) (count pt)))
      (let [p (distinct (map vector ct pt))
            ctc (count (distinct (map first p)))
            ptc (count (distinct (map last p)))]
        (= (count p) ctc ptc))))

and in a REPL, it's very easy to see that it's working:

  (matches? "wdllpy" "rabbit")
    => true
  (matches? "wdllpd" "rabbit")
    => false 

I have to admit that clojure is about the most fun language that I've used in a very long time. Ruby is nice, and it's very close - but clojure is just functional - and performant - all the way.

[12/12] UPDATE: my friend wrote me back with a significant simplification to the code:

  (defn matches?
    "Function to see if the cyphertext and plaintext have the same pattern of
    characters such that they could possibly match - given the right legend."
    [ct pt]
    (if (and (string? ct) (string? pt) (= (count ct) (count pt)))
      (let [pc (count (distinct (map str ct pt)))
            ctc (count (distinct ct))
            ptc (count (distinct pt))]
        (= pc ctc ptc))))

I was worried about doing this, initially, because I was thinking that it would be possible to re-arrange the letters while keeping the number of distinct characters the same, and therefore make additional possible matchings that would make it impossible to match.

What I realized with his help is that the key is that we have three checks - the pairs, and the distinct chars in the words. With all three, it's going to catch all the cases I was worried about.

Also, I really like how he went to using str as opposed to vector. Very nice. Just as effective, but far cleaner and easier to deal with in the distinct.

I can then go back and look at the ruby code and update the constructor for the CypherWord:

  def initialize(cyphertext)
    @cyphertext = cyphertext
    @cyphertext_chars = cyphertext.chars
    @cyphertext_uniq_count = cyphertext.chars.to_a.uniq.count
  end

and then the matches_pattern? becomes the simpler:

  # One of the initial tests of a plaintext word is to see if the pattern of
  # characters matches the cyphertext. If the pattern doesn't match, then the
  # decoded text can't possibly match, either. This method will look at the
  # pattern of characters in the cyphertext and compare it to the pattern in
  # the argument and if they match, will return true.
  def matches_pattern?(plaintext)
    return false unless @cyphertext && plaintext &&
                        @cyphertext.length == plaintext.length
    pc = @cyphertext_chars.zip(plaintext.chars).uniq.count
    ptc = plaintext.chars.to_a.uniq.count
    (pc == @cyphertext_uniq_count) && (@cyphertext_uniq_count == ptc)
  end

Yeah... we're beating this Bad Boy into the ground, but it's a lot of fun to be working with my friend on something - even if it's just a 30-year olg problem.

My Favorite Time of the Year

Wednesday, December 10th, 2014

Christmas Tree

This morning I got in and fired up my favorite Christmas song playlist and plan to just listen to it over and over all day long. This is my favorite time of the year. I love the music, it makes me feel peaceful, and thankful, and that's a really good place to be.

Every day is not going to be perfect. There are times things still get me a little down... OK, there are times that things get me a lot down, but as long as I can stay focused on the meaning of Christmas, and why we are here, then it doesn't last long.

I don't have a big christmas tree like I used to. But the little tree I have now I leave up all year around because I don't want to let go of this feeling. It makes me feel better to see it each day, and hopefully very soon I'll be at peace much more of the time. But life is what it is, and I need to just keep moving.

But I am blessed. Very blessed.

Christmas Tree

This was the last family Christmas Tree I had... and it was very beautiful.

The Tree of Problems

Monday, December 8th, 2014

Great News

I don't remember who told me this story, but it's an interesting tale that has really hit home this morning as I've been reading some of the posts I wrote in the last month. The story is about The Tree of Problems, and it goes something like this:

At the end of each person's life, they walk up to The Tree of Problems where every person takes all their problems - as a group, and hangs them on the tree. Then they walk around to see what set of problems they would like to have in their next life, and after looking at all the problems on the tree, they pick theirs back up.

Because they realize they can deal with these problems best.

And it's really just a statement that when we look at people, and think they have no problems, that's because we aren't really seeing what their life is like. We are only seeing this tiny slice of their life that they choose to expose to us. And the real issues are not something that we really almost never see, because most of us really try to hide those bad problems from others - even friends and family.

I'm currently in the middle of this job search. It's going well. I'm hoping to have something all lined up before the first of the year, but I'm trying to manage my expectations as well. This all relates to The Tree of Problems in that I've not been happy at work for a while. A long while. I can look at posts going back a while, and while there are times when the work was fun and exciting, the environment I'm working in is really not something I like.

Yet I held onto it far too long.

I kept thinking "It'll get better"... or "This is the system I know"... when in reality it's not going to get better, and in fact, it's getting worse. Not because the people are mean or nasty - just because they share different values that I do, and there isn't a group in Chicago that appears to share my values.

This also reminds me of Liza. Loving and marrying the wrong person is a recipe for the same kind of grief. You think "I'll work harder"... or "I'll stop doing this for them"... or any of a million other things, all of which don't matter because ultimately, they aren't interested in being with you. It's a bad fit.

So I need to Let Go... as Richard Bach said in Illusions... let go of the rocks I'm clinging to at the bottom of this river and trust that the river knows where it's going, and will carry me along. It's not all that easy, but nothing of value is. Letting go and having a little more faith is what I need, and this morning it was just so clear that people hold on all the time.

So I just need to cut myself a little slack and try and relax as I see where my path is headed.

Refreshing my Ruby Skills

Monday, December 8th, 2014

Ruby

Last week I was in an interview where they wanted me to code in Ruby - nothing else. I wasn't really prepared to write Ruby, as it's been a good 18 months since I've written a line of it - maybe more. But I excused my poor memory of the syntax and dug in. But it got me thinking, and I decided to brush up on my Ruby skills, and have a little fun at the same time.

So I made a new directory, and started grinding the gears on my memory to get things back in line for working on Ruby. This means remembering rvm, and how to even find the version of Ruby for the .ruby-version file in the root of the project. Then there were the .rspec lines for getting nice looking test output - and running the tests in random order every time. And I still hadn't gotten to the code.

So I started working on the programming task I got in the interview, and it was really amazing to me that some of the hints I'd gotten in the interview were really not at all how I wrote it when I had the chance to do it on my own. For example, I needed to take a string, and get the first character, and then the rest - very much like clojure would do it. I was given the hint that "hello".chars would give me an Array of the characters, and on their box it did - but in Ruby 1.9.2, it returns an Enumerator, and that's an entirely different thing. Also, it requires that we allocate new storage.

What I really wanted was: "hello"[0,1] - that's a string of the first character in the string. And then the rest is just: "hello"[1,10], or another long number to get the rest. This is what was sitting in the back of my memory, and when I saw it, a lot of other little things started flooding back in.

Things started accelerating, and in no time I was looking at a far cleaner version of the test code I'd written just a few days ago. Far more idiomatic Ruby, and the tests were super simple to write, and took advantage of the contextual nature of the tests.

I'm not going to claim that I'm even a decent Ruby coder. I'm just fair. The class library is just far too expansive to know it all without dealing with it on a daily basis, and even then, on a large codebase that takes advantage of the different classes as well. It's vast. Which is nice, don't get me wrong, but it's why I know it'd take me a very long time to master even where things are - let alone their syntax and usage. But it's something I may have to do, so it's nice to get back in it.