Why your back-end tools should be sexy, too

If your internal tools aren’t the same quality and sexiness as your client-facing tools, then your employees aren’t going to be as excited as they could be and won’t be selling your company as well as they could.

While working at Bookr, our design motto was “dead simple; dead sexy.” It’s something that I think is a great, simple goal that most everyone in the company can eat least target. We applied this to our product and customers loved the way it looked. I’ve carried that through (internally) for Blueprint, although I don’t think that “sexy” quite fits our brand here as it did for Bookr.

On almost every project I’ve worked on, we put a lot of effort on client-facing parts of the product and tools that are used internally (often called “admin” screens) just don’t get the same treatment.

Have you ever called up a company on the phone and had to wait while the representative has to navigate an extremely complex system or set of systems to get your information? Ok, have you ever called a company at not had that experience? Doesn’t that frustrate you as a customer? Quite often, I’ve had representatives apologize for the poor quality or capabilities of their software. As a software developer, I don’t want this ever to happen with my products.

So in the last two companies, I’ve been working to promote as much, or nearly as much, effort on the design and thoughtfulness and usefulness of “admin” screens as I do on the client facing stuff.

For Blueprint, not only are our clients using the product directly, but account managers and analysts use the product for consultative services. They get the benefit of client-facing tools, but when they cross into the “admin” parts of the site I don’t want them to feel put off.  We are constantly looking at the tools we have built for managing, tracking and maintaining client accounts and client information — tools that clients don’t have access to — and they way we use those tools to try to make sure they can be simple and sexy.

Why you maybe shouldn’t praise employees’ talent

In a series of studies Carol Dweck (with C. M. Mueller, 1998)[1] found that praising students’ abilities conveys “that their ability is a gift and makes them reluctant to take on challenging tasks that hold a risk of mistakes.”[2]

I recently read Why Aren’t More Women in Science?, which a was surprisingly interesting, especially as learned scientists and researchers come to different conclusion to answer the question posed in the title. There is a lot of interesting information in there about behavioral science and I recommend reading it if you are interested in technology, women in technology, and the recent push for STEM instruction in schools.

However, I found the results of Dweck’s 1998 study to be surprising and contradictory to almost all advice in both teaching and management. What Dweck discovered though, actually makes sense. If you praise an individual for an innate ability (talent, intelligence, etc.), then she may be reluctant to risk losing your esteem in her that you have suggested is related to something that she cannot change.

This doesn’t mean you should’t praise people though. I think that what Dweck suggests is that you should praise people for what they’ve accomplished — for a job well done — rather than suggesting that they are naturally good at it. As I’ve tried to look at my practice of praise (which I continually work on) I find that this is hard, because I want to recognize individual strengths (First Break All the Rules was my first management bible).


[1] Mueller, C. M., & Dweck, C. S. (1998). Intelligence praise can undermine motivation and performance. Journal of Personality and Social Psychology., 75, 33-52.
[2] Dweck, C. S. (2007). Beliefs That Put Females at Risk. Why Aren’t More Women in Science? Washington, D.C.: American Psychological Association.

Emotional search with Twitter

I’ve been reading the Twitter API docs and just discovered that Twitter lets you search based on the tone of the tweet using emoticons. For example, type this search:

#829strike :)

Twitter returns tweets about the Fast Food strike on 8/29  with a positive attitude.

If you want to see the other side of the the emotions, use a frowny face.

#829strike :(

This works on Twitter Search as well as through the API.

Using emoticons as operators to represent attitude is pretty cool.

Yes, it turns out Windows 8 is relevant

Meeker 2012 p24Here in Seattle among small tech companies (or start-up), and among pundits worldwide, people like to say that Windows is irrelevant. They point that slide (#24) in Mary Meaker’s State of the Internet last year (or slide #109 in this year’s deck, although it looks like that’s missing the Apple segement) that shows that Microsoft dominated computing platforms for 20 years and is being replaced with iOS and Android. They say that Windows 8 isn’t important and the Windows Phone 8 will never gain the market share that Apple and Android have.

I’m sure that there is lots of research to backup these claims (Gartner and IDC chimed in after all), but flat design is pervasive. The big news this week out of WWDC is that Apple’s iOS 7 has moved to flat design. Android 4 dropped skeuomorphic elements 18 months ago, even changing the text box to a single line. The latest Gmail for Android looks like Windows Phone 7, with quartered avatars that are incredibly reminiscent of the Metro tiles.

Zune 2007All that started at Microsoft. The elements that Microsoft built on for Metro were hatched in the Zune “chromeless” interface Method designed in 2007, carried into Windows Phone 7 and then Windows 8. The Metro interface has gotten tons of not-very-friendly press, but it’s clearly made an impact on the world.

So when the entire world of design is changed based on ideas coming out of Windows and Microsoft, I find it disingenuous to claim that they are not relevant. I couldn’t say whether Windows 8 is selling well enough for Microsoft, but it’s certainly making it’s mark.

We fixed rails redis store to rapidly expire 50,000 keys daily from a 3.5M key cache

In building out Blueprint, we have taken an approach of “cache everything” (or what we think is most important) to make the app super responsive. Our customers love this.

What we actually cache is, essentially, a data digest used in the reporting view (so not the view or the model per-se). These digests could be a daily, weekly, monthly or annual view of a perspective on a data cube. Each day we add new, updated data to our cubes and need to expire the cached items that pertain to that day (e.g. latest week, month, year). In addition, we’re often recalculating categorizations for clients which means expiring their entire cached history and rebuilding it.

And so, we will expire 50,000 cache keys each morning as we push in new data (and then we go rebuild them). For a given site we might delete 1000-2000 keys.

Up until this week we used the delete_matched method to remove all of the site’s keys in a single call (optimizing our redis time). However, delete_matched relies in the redis keys method which is slow, blocks the redis server and isn’t meant to be used in production. In fact, I could watch our redis server’s CPU go from 0.1% to 100.0% exactly during the call to expiring site caches. Because redis is mostly single threaded, pinning the CPU for processor-heavy operations holds back all the fast GET calls from our cache reads and slows the site to a crawl.

The solution was clearly we couldn’t rely on redis to tell us what keys were in the cache. Michael and I whiteboarded this and built (well, Michael mostly built) a replacement cache store that inherits from RedisStore and effectively does three changes: stores the key name into a set (we partition sets, which is hidden in the code below) when the cache entry is written, remove the key name from the set when the cache entry is deleted, use the set to find the matched keys for delete_matched and remove those from the cache and the set.

      def delete_matched(pattern)
        sub_set = find_matching_keys(@set, pattern)
        Redis.current.srem(@set, sub_set)
        Redis.current.del(sub_set)
      end

      private

      def write_entry(key, entry)
        Redis.current.sadd(@set, key)
        super
      end

      def delete_entry(key)
        Redis.current.srem(@set, key)
        super
      end

I was pretty surprised not to find other solutions for this already or that the redis-store implementation doesn’t do this automatically. However, when we implemented it, the tricks in partitioning the set (to keep that read time low) lead me to believe it’s not a generalized solution (although you could use hashing to generalize it). We also had to build a process to build up the set from the existing 3,541,239 keys in our cache, so we’ll see if that takes the weekend or just the night.

Nginx maintenance page configuration with load-balancer health check

We wanted to add a maintenance page to our rails app running on nginx. Capistrano provides a simple task to show your maintenance page cap deploy:web:disable. It includes basic instructions for how to configure nginx, although I found these didn’t quite work for us as documented.

One thing the configuration suggests it to return a 503 status code so that crawlers know the site is temporarily down and will retry the crawl later. This made sense, but when we did this in front of the load balancer it automatically sent it’s own 503 to the browser because it detected that the app server was returning 503 (which is what it should do, or roll over to another server). What we needed was the ability to have our load balancer run it’s health check on the app server without getting the 503.

While I have read that that “If is evil” in nginx configurations, I found that I could check whether the request was the load balancer and return a 200 code within the maintenance handler:

        if ($request_filename ~ '/health_check') {
          return 200;
        }

I also learned a lot from this older post (like how to allow inclusion of graphic assets such as our logo). But the key trick was to put a bare ‘=’ on the error_pages line so that Nginx would return the handler’s response code, rather than 503 for all pages.

      error_page 503 = @maintenance;

Here is the entire configuration that we used (put this at the server level).

      recursive_error_pages on;
      
      if (-f $document_root/system/maintenance.html) {
        return 503;
      } 

      error_page 503 = @maintenance;
      location @maintenance {
        error_page 405 /system/maintenance.html;

        if ($request_filename ~ '/health_check') {
          return 200;
        }

        if (-f $request_filename) {
          break;
        }

        rewrite  ^(.*)$  /system/maintenance.html break;
      }

Microsoft Office for Mac: How not to design your installation experience

I needed PowerPoint to change files for a project so I went to grab a copy of Office. Not only did I have to download the entire 900MB package of Office (instead of just the PowerPoint app I wanted) it had a terrible first experience. Each time I try a Microsoft product these days, it just feels so clunky. Where’s the aesthetic and pleasing design? I know they can do this.

It’s simple things like the email they sent me from “OFFIE.OESD.WW.00.EN.SIT.BAG.CS.T01.RTG.00.EM@css.one.microsoft.com” (which of course is what you see your email software first) rather than adding a name like “Microsoft Office”.

Or the installation itself. I downloaded a copy of the software (which, for what it’s worth, “2011” makes it feel old by now when everyone else is updating software o 6-week schedules) and installed it. Then it immediately required a critical update. And another one. And a third one. During the course of which I wasn’t allows to have any browsers open. If I just downloaded your software why doesn’t it have all the critical updates?

I think the final frustation of bad user experience was when all the updates where done. The updater presented a dialog that made me feel like having no updates is a bad thing. Apple does the same thing with their automatic updates (incidentally, Apple “fixed” this in Mountain Lion by running updates through App Store which has it’s own problems). Why not just close the updater if there are no more updates? Really, I’m not that emotionally attached to my software updater that I need a modal dialog to tell me it’s all fresh. Oh, and when I clicked “OK”? It still didn’t close; I had to quit the updater app.

Sorting addresses treating numbers numerically

I was working on a small sorting task where we wanted to sort entries like these:

1 Sesame St
2 Sesame St
12 Sesame St
Building A
Building Z
Suite 1
Suite 2
Suite 100

As you can see this probably is what you’d expect — the numerical parts of the strings are sorted numerically. But standard string and number sorts don’t do that. So I worked out a quick compare routine for using in sorting and thoughts I’d share it.

        public static int Compare(string a, string b)
        {
            var numberA = ""; 
            var numberB = "";
            int cmp, ap = 0, bp = 0;
            char ca, cb;

            while (ap < a.Length && bp < b.Length)
            {
                ca = a[ap];
                cb = b[bp];

                bool aDigit = Char.IsDigit(ca);
                bool bDigit = Char.IsDigit(cb);

                if (aDigit && bDigit)
                {
                    // Create a number from all contiguous digits in string a
                    do
                    {
                        numberA += ca;
                        ap++;

                    } while (ap < a.Length && Char.IsDigit(ca = a[ap]));

                    // Same for string b
                    do
                    {
                        numberB += cb;
                        bp++;

                    } while (bp < b.Length && Char.IsDigit(cb = b[bp]));

                    // Compare the numbers numerically
                    cmp = Int32.Parse(numberA) - Int32.Parse(numberB);
                    if (cmp != 0)
                    {
                        return cmp;
                    }
                    numberA = numberB = "";
                
                    // If they match look at the characters following them
                    cmp = ca - cb;
                    if (cmp != 0)
                    {
                        return cmp;
                    }
                    ap++;
                    bp++;
                }

                else if (aDigit)
                {
                    return -1;
                }
                else if (bDigit)
                {
                    return 1;
                }
                else
                {
                    cmp = ca - cb;
                    if (cmp != 0)
                    {
                        return cmp;
                    }
                    ap++;
                    bp++;    
                }

            }

            return a.Length - b.Length;
        }

I have to apologize that there’s no test code for this. But I hope it’s helpful to some. Should be easy enough to translate to other languages.

Are the Millennials Inherent Leaders?

I recently read an article on NPR talking about how the “‘Globals’ Generation Focuses On Experience”. Part of the article that really struck a chord was that the 28-year-old “global” in the article talks about supporting others and listening as a key core value:

“My American dream is for other people to be able to achieve whatever they want to achieve,” [La Mikia] Castillo says. “It’s not really about me and what I have as an individual. It’s about trying to make a difference around the world.”

This idea of empowering your team is something that leadership books and articles have been pushing for a long time (e.g. First Break All the Rules (specifically about focusing on employees’ strengths and helping them be the best they can, “Are You Interested?”, “Non-hierarchical Management”). It’s been core to my ethos as a manager for years (and therefore something I’m alway trying to get better at) and there’s certainly a lot of talk about it, but you don’t often see it in action.

Now maybe I’m mixing up my generations (is ‘Globals’ different than ‘Millennials’?) but I remember hearing traditional leaders claiming this to be a generation of people who believe in “entitlement”. Specifically, that they expect certain attitudes at the workplace or expect a ping-pong table and beer in the fridge or expect to be paid whether they hit their goals or not.

This contrast in attitudes is interesting. It certainly sounds like a standard generational gap response (“kids these days…”), but I think there’s something more going on. If you had built your career in a “traditional” leadership style where respect was given based on rank, salaries were set based on rank and your personal goals or accomplishments determined your bonus and success in the workplace, you might find the actions of someone with the attitude quoted above to appear misaligned with your goals and therefore appearing to be “entitled” to benefits of a job beyond the work that you see them doing.

The other parts of the article implied that this is a representative attitude borne of a more globally connected generation. I hope that’s true because I think this cultural belief, coupled with the interest in non-hierarchical management (specifically, Valve or Ciplex) is going to lead to some really interesting changes that are critical to maintaining innovation in America in the future.

Fire-roasted Vegetables with Polenta Timbales

Flipping through Deborah Madison’s Vegetarian Suppers cookbook, I was inspired by the prep photo for one of her meals. It showed roasted garlic, peppers and tomatoes. In her recipe those are pureed and poured over pasta, but I wanted to eat them whole (or nearly). And it seemed polenta would be the perfect accompaniment.

Serves two to three.

For the polenta timbales

4 cups water
1/4 tsp salt
1 cup dried polenta cornmeal
1 tbsp butter
1 ounce shredded medium cheddar

Bring the water to a boil in a heavy 3 quart pot. Immediately turn the heat down to medium, add the salt and then slowly pour in the polenta whisking while you pour. Continue to stir for a few minutes until the polenta thickens. Turn the heat to low and continue cooking for 40-45 minutes, stirring frequently and adding water if it becomes to thick.

Just before serving, add the butter and stir when melted. Then add the shredded cheese and stir in until combined. Adjust seasoning.

Scoop the polenta into small ramekins or bowls, about 1-1/2 cups per person. Invert the bowls on the center of the serving plates. You can leave the bowls on while you plate the rest of the food.

For the fire-roasted vegetables

4 Roma tomatoes
4 cloves of garlic, skin left on
1 tbsp olive oil
3 dried Guajillo chiles
1 dried ancho chile
1/3 cup chopped onion
1/3 cup chopped celery
1 avocado
Sour cream
2 tbsp parsley, roughly chopped

Place the tomatoes and garlic in a cast iron skillet, drizzle with olive oil. Roll the garlic and tomatoes in the oil in the pan coating all sides. Place the skillet under the broiler and broil on high for 20-30 minutes, rotating the tomatoes and garlic as they roast. Remove the garlic from the plan as when it’s blackened on all sides. Continue roasting the tomates until blistered and slightly blackened. Remove and set aside.

Meanwhile, hold the chiles over a a flame with tongs and lightly toast each side, approximately 30 seconds. Extinguish them immediately if they catch fire. Place them into a small dish with a little bit of hot water to soften and let sit.

Place the same skillet on the stovetop on low and add the onion and celery and a little more oil if needed. Saute on low until the the onions and celery are softened.

Take one roasted tomato, one roasted Guajillo chile and place in a blender. Squeeze the garlic out of the skin and add to the blender. If any liquid has collected from the reserved tomatoes add this to the blender as well. Pulse and then puree until smooth. Pour this into the pan with onions and celery and heat to combine.

Slice the remaining tomatoes in half placing them cut side down around the polenta timbale on the plates. Pour the sauce over and between them. Trim the top of the chiles, pour out the seeds and then thinly slice them. Distribute the softest rings around the plate. Place dabs of sour cream around the plate. Gently tap and shake the timbales out of the bowls. Place two or three slices of avocado against the timbale and sprinkle the whole plate with parsley.