Posts

  • You get what you measure

    This is a short post on how measuring performance can backfire. So you are trying to foster a culture and you decide to measure how close (or far) your organization is from that culture. Although your intentions are good, your efforts can backfire. You can end up with a culture that is the opposite from what you intended in the first place.

    We will walk through two ideas which, put together, lead to the concept of “you get what you measure.” We then close with what this could mean for your organization.

    Measurement influences behavior

    Think about the difference between measuring the length of a house versus measuring people’s kindness. Unlike measuring inanimate objects, measuring adaptive systems is difficult. An adaptive system is a system that reacts to being measured. So, the act of measuring influences the outcome.

    Different from measuring length of inanimate objects, if you measure people’s kindness, people will tend to act kinder. You can never get to the actual truth–there will always a bias in the measurement. That can be good. By measuring kindness, kinder people. Win!

    A measurement is a proxy, not the actual attribute

    The second idea is the idea that a measurement is a proxy, and a proxy is not the actual attribute.

    Going back to kindness, how would you measure it? Kindness is an abstract concept. You can’t measure it directly, but you can try to quantify it by measuring a proxy for kindness.
    For example, maybe you measure whether a person makes charitable contributions, whether they sent you a message on your birthday, or whether they tend to hold the door for the next person coming in line.

    This Zen buddhist saying “don’t mistake the moon by the finger pointing at the moon” can help us remember the distinction between an attribute and it’s proxy.

    You get what you measure

    So, the combination of (1) adaptive system and (2) measurement-by-proxy has a catchphrase: you get what you measure. Here is an exaggerated example:

    You have a customer support center where people look into tickets created when a customer calls with a complaint. You want to measure and improve the quality of this organization.

    If you measure quality by how fast tickets are closed, analysts will find the easiest answers to the complains and close the ticket with “xyz is likely the culprit” without doing due diligence. So customers will have to call back with the same complaint, and new tickets will be opened for the same issue. On paper, you are closing tickets faster than ever! In practice, your customers are getting pretty frustrated because their problems are not being addressed.

    Say you decide to measure quality by how fast tickets are responded to (as opposed to how fast they are closed). Then someone will create a bot that fills the new tickets with messages like “Looking into it..” All tickets get an initial response, never mind the fact that the response is useless.

    Once you have put a system in place to measure (1) an adaptive system that (2) can only the quantified via a proxy, then you get what you measure. And what you measure is not necessarily what you want to foster. No matter how complex you make the metrics, there will come a point where optimizing for the metric will clash with simply “doing the right thing.”

    Over time

    You are probably thinking: “That’s a pretty cynical view on people!” or “The people I work with are not like you describe”. You are right! Your employees or co-workers are not like that.. at least not now. But they may become more selfish once you put a performance measurement system into practice. The reason is that performance measurement systems put people on the spot. They have to solve a dilema: do I improve the metric or do I “do the right thing”?

    May people will be altruistic. They want to do the right thing. Plus, if the company isn’t doing well, no one will do well. So it’s logical to look after the health of the company. But one bad apple is all it takes to shift behavior.

    Although you may not notice when one person in your organization puts benefiting themselves over “the right thing”, other closer by will. People have beliefs and values (call it a compass), and they will not change their behavior because of one or two more self-centered individuals. Many of your employees will keep doing “the right thing”, but a few of them may decide to “do the right thing” somewhere else. Over time, the frustration of seeing a bad apple benefitting themselves will crumble your employees’ motivation . They will get tired of being put on the spot and forced to choose between “the right thing” and the metric. You can’t blame them. It’s not a fair situation to be in in the first place.

    So, over time, the system will select for the less altruistic of us, and eventually the company will look the opposite of what the performance-measurement system intended to foster.

    What then

    Okay.. but if we shouldn’t measure performance, what can we do instead?

    If the goal is to foster behavior, then create a culture that allows for this behavior to flourish. The shift is from measuring people to enabling them. Embrace the fact that none of this is a hard science, and stop trying to put a number on something that can’t be properly quantified. Encourage discussions on culture instead.

    continue reading...
  • Go, Scala and case classes

    In this blog post, we will take a look at Go and Scala, and specifically, at their approach to case classes.

    One of Scala’s key features is its support for case classes. Case classes are meant for holding immutable data. They are similar to regular classes, but they come with a number of useful features out-of-the-box, such as the ability to generate a toString method, a copy method; they also come with matching support.

    Here’s an example of two case classes, Dollar and Euro, that extend a common Currency class in Scala:

    abstract class Currency(val name: String, val alpha: String, val symbol: String)
    
    case class Dollar() extends Currency("US Dollar", "USD, "$")
    case class Euro() extends Currency("Euro", "EUR", "€")
    
    val dollar = Dollar()
    val euro = Euro()
    
    println(dollar.name)   // Output: US Dollar
    println(dollar.alpha)  // Output: USD
    println(dollar.symbol) // Output: $
    println(euro.name)     // Output: Euro
    println(euro.alpha)    // Output: EUR
    println(euro.symbol)   // Output: €
    

    Go, on the other hand, does not have built-in support for case classes. We will look at three different approaches that can be used instead:

    1. structs
    2. enums
    3. interface and “empty” types definitions
    continue reading...
  • Yesterday I defended the PhD

    As cliché as it sounds, the story of my PhD started in my childhood. Growing up, I wanted to be a scientist. In my teenage years, I had my eyes on a joint math and physics program at the Universidade Estadual de Campinas (UNICAMP), Brazil. I started the program in 2001 and still remember Professor Alcibíades Rigas class on linear algebra and analytical geometry. Rigas used a graduate level book written in English as the main resource for this freshman level course—in a country where most don’t speak English. It’s an understatement to say that the class was hard. But rather than an exercise in gratuitous punishment, Rigas helped us build a solid foundation. I fell in love with the campus and the program, but I left midway through my freshman year. While taking entrance exams in Brazil, I had also submitted applications for college in the US. When notified of my acceptance at the Rochester Institute of Technology (RIT), I chose the unknown over a life I had been falling in love with.

    continue reading...
  • Concurrency, Distribution, and the Go memory model

    The Go memory model specifies two main ways in channels are used for synchronization:

    1. A send onto a channel happens-before the corresponding receive from that channel completes.
    2. The $k^{th}$ receive from a channel with capacity $C$ happens-before the $(k+C)^{th}$ send onto that channel completes.

    Recall that happens-before is a mathematical relation, as discussed here.

    Rule (1) above has been around for a while. The rule is very similar to what was originally proposed by Lamport in 1978. It establishes a happens-before relation between a sender and its corresponding receiver. Rule (2) is a bit more esoteric. It was not present in Lamport’s study of distributed systems. There is a good reason for that absence.

    continue reading...
  • Channels vs Locks

    With channels, we typically establish that two things are synchronized because A happens-before B. We often know the order in which they happen. In this post, we’ll see a use (or “misuse”) of channels. We will be able to establish that two things are synchronized, but we won’t know the order between them. We won’t know which happened first. We will then relate and contrast channels with locks: how are they different, how are they similar.

    continue reading...
  • What makes Go special

    goroutine What stands out the most in Go, to me, are goroutines and channels. The language was built for the many-core. It sprung from the observation that processors are not getting much faster at doing one thing, but are becoming faster by doing many things at once. To benefit from this trend, we ought to write multithreaded applications. Go makes it super easy to have multiple threads of execution. By prepending the keyword go at invocation, any function can run asynchronously (on its own “thread”). For example, the program below has only one goroutine, the main goroutine.

    continue reading...
  • Rhubarb tang

    If you are following the blog, you have been busy learning about memory models. We started from the basics: what are memory models? What’s interesting and challenging about them? Then covered weak memory and got to the point of introducing the concept of happens-before relation. With that, we visited a real-world memory model specification, that of the Go programming language.

    Pat yourself on the back. Great job! It is time to take a refreshing break. In my welcome post, I said I would share some (drink) recipes. Here is one for the summer. I call it “rhubarb tang”.

    continue reading...
  • The Go memory model

    The Go memory model starts with the following ominous trespassing sign:

    If you must read the rest of this document to understand the behavior of your program, you are being too clever.

    Don’t be clever.

    Feeling clever? Then come on in!

    continue reading...
  • The happens-before relation

    At the end of the previous post, we saw that a compiler can change the order of instructions in a binary (as long as single-threaded semantics is preserved). These changes can break synchronization, especially if we expect to synchronize by reading and writing to variables. When pondering about synchronization, it would be unreasonable to expect a programmer to peek into the compiler. Luckily, languages come with a memory model: a document that serves as a contract between the programmer and the compiler.

    Memory models are often defined in terms of the happens-before relation.

    continue reading...
  • Weak memory models

    In the previous post, we touched on consequences of our quest for performance. We saw that, by relaxing the order of execution of instructions, compilers are able to produce faster binaries, and processors are able to execute these binaries faster. We want this rearranging to be done for us because efficient instruction scheduling is a science in itself. Also on the previous post, we touched on the concept of sequential consistency.

    In this post, we will discuss single-threaded semantics, compositionality, and their relation to weak memory models.

    continue reading...
  • An introduction to memory models

    In this series of posts we will visit the concept of memory models using “real-world” examples. We will look behind the scenes and into a programming language’s implementation. We will see how the specification of the memory model relates to the language’s implementation.

    Below we cover some basics: what is a memory model and why do these models matter. We will touch on concepts associated with multi-threading and synchronization, such as the concept of sequential consistency, weak- or relaxed-memory, atomicity, etc. In future posts, we will discuss the Golang memory model and we will look into Go runtime source code. But first, a confession.

    continue reading...
  • Starting with a fizz!

    Welcome! I want to share with you some things I’ve learned about computer science. I hope to spark conversations, meet people, and have a bit of fun along the way. I will try to strike a balance between practice and theory, rigor and accessibility. I hope you’ll enjoy.

    My first “serious” post is about memory models, but before we start, here is a drink recipe that is as much revealing about my origins as it is tasty.

    continue reading...

subscribe via RSS