code – BKM TECH / Technology blog of the Brooklyn Museum Tue, 19 Apr 2016 14:30:13 +0000 en-US hourly 1 https://wordpress.org/?v=5.5.3 Leveraging Machine Learning for Better Efficiency /2016/04/19/leveraging-machine-learning-for-better-efficiency/ /2016/04/19/leveraging-machine-learning-for-better-efficiency/#respond Tue, 19 Apr 2016 14:30:13 +0000 /?p=7868 Extremely smart people dedicated to the field of machine learning have made tools that are not only better, but far more accessible than they have been in the past. We don’t have anyone at the Brooklyn Museum who’s an expert in machine learning, but because of the improvements in machine learning tools, we don’t have to be. If you’ve been following our series of blog posts you’ll remember we talked previously about the accuracy issues we’ve had with iBeacons and the problems that poses for usprimarily that decreased accuracy in iBeacon results means delayed response times to visitor questions. Since providing a seamless, personal, educational, and ultimately extremely rewarding experience is the foundation of what ASK Brooklyn Museum is built upon, anything we can do to improve the efficiency of the system is a project worth taking on.

One of the tools we’ve leveraged to help us in this goal is called Elasticsearch which is a full text search server.  While not strictly just a machine learning tool, it uses many NLP algorithms (which are machine learning based) in its backend to do more intelligent text searching to match similar phrases. This means instead of doing a ‘dumb’ search that has to match exact phrases, we can do more fuzzy style searching that can locate similar phrases. For example, if we have a block of text that has the phrase ‘Where are the noses?,’ if we did a search using the phrase ‘What happened to the noses?,’ the first block of text would be returned near the top of the results.

This particular use case is exactly what we were looking for when we needed to solve a problem with our snippets. We’ve talked about snippets in a previous post, but just to recap snippets are pieces of conversations between visitors and our audience engagement team about works of art in the museum. Due to their usefulness in not just highlighting great conversations, but also in their acting as a sort of knowledge base, snippets have become an integral part of ASK. This means we’d like to create snippets as much as we can to grow this knowledge base and help spread the wisdom gleaned from them. However, over the course of this process it’s easy to accidentally create snippets for the exact same question which clutters the system with duplicates.  This is problematic not just for search results but also because all snippets go through a curatorial approval process and seeing the same snippets creates unnecessary extra work for everyone involved.

The dashboard automatically queries our Elasticsearch server to look for similar or duplicate snippets during the snippet creation process.

In addition to solving the problem with duplicates, cleaning up the system means we can much more accurately track the most commonly asked questions.  All of this happens as part of a seamless process during snippet creation.  When an audience engagement team member begins the snippet creation process, the dashboard automatically queries our Elasticsearch server to look for similar or duplicate snippets.  These search results show up next to the snippet editor which makes it easy to quickly find if there are existing duplicates.  If a duplicate snippet does exist, the team member simply clicks a “+1” counter next to the snippet.  This increments a number attached to the snippet which we can then use for various metrics we track in the system.

If the ASK team finds a duplicate snippet does exist, they click the “+1” counter. This increments a number attached to the snippet which we can then use for various metrics we track in the system.

Just based on our short time using machine learning tools, it’s clear how powerful the advantages of using these tools are in the here and now.  We’ve already talked about how they’re already improving our response times, metrics, and knowledge base, but that may just be the tip of the iceberg.  The AI revolution is coming and as tools get more sophisticated yet simpler to use, the question isn’t if you’re going to use it, but when and how?

]]>
/2016/04/19/leveraging-machine-learning-for-better-efficiency/feed/ 0
Performance Optimization, Not Premature Optimization /2015/06/18/performance-optimization-not-premature-optimization/ /2015/06/18/performance-optimization-not-premature-optimization/#respond Thu, 18 Jun 2015 16:15:32 +0000 /?p=7581 At the Brooklyn Museum, we like to take inspiration from many things. After recently watching “Mad Max: Fury Road,” we realized to make our servers go faster, we should have a dedicated staff member spit gasoline into a combustion engine connected to one of our servers…vroom vroom!

Nitrous makes cars go faster.  Servers not so much.

Nitrous makes cars go faster. Servers not so much.

All jokes aside, for most consumer/public facing apps, performance is a very serious consideration. Even if your app has the best design, bad performance can make your Ferrari feel like a Pinto. While performance can mean many things in a technical context, in this post I’ll just be talking about the performance of our back-end.

As I mentioned in an earlier post, we use an internal API to power both our mobile app and the dashboard our Visitor Engagement team uses to chat with visitors. This API has to be able to not just handle requests, but do it in a very performant way. This is especially true given the nature of ASK which revolves around a real-time conversation between visitors and our Visitor Engagement team.

When taking performance into consideration, it’s easy to fall into one of the deadly programming sins: premature optimization. Premature optimization is what happens when you try to optimize your code or architecture before you even know if, when, and where you have bottlenecks. To hedge against this, the solution is simple: benchmark your application. Since I’m just talking about the back-end in this post, application in this context means our API.

When we benchmark our API, we’re not just benchmarking the webserver the API is being served from; we’re benchmarking every component the API is comprised of. This includes (but not limited to) our webserver, API code, database, and networking stack. While our back-end is relatively simple by industry standards, you can see from this list that there are still many components in play that can each have an impact on our performance. With so many factors to account for, how do we narrow down where the bottlenecks are?

Similarly to power plants, back-end servers also need to be able to meet peak demand.

Similarly to power plants, back-end servers also need to be able to meet peak demand. photo credit: 2009-09-10 AKW Gundremmingen via photopin (license)

Well first we have to ask ourselves, “What is an acceptable level of performance?” This is a question you can’t answer fully unless you also add the variable of time to the equation. Similarly to the way power utility companies determine how much electricity they need to generate, we also look at the same thing: peak load (see also: Brown Outs). Peak load is simply how much load do you anticipate having during the busiest times? If we know our system can handle peak load, then nothing more needs to be done in terms of optimization.

In practice, our real bottlenecks are most likely to be the human element of the equation: our Visitor Engagement team. Since we only have a few working at any given point in time, and the fact that quality answers can sometimes take a little while to come up with, having too many people asking questions and not enough people answering can be our worst bottleneck at times. That being said, when we’re optimizing for a certain load average on our backend, we didn’t want to just aim for that number; we wanted to aim a bit higher to give ourselves some cushion.

So how do we actually figure out where our bottlenecks are? In essence, this is a basic troubleshooting problem. If something is broke, where is it broke? Often times the simplest way to figuring this out is by isolating each component from each other and benchmarking each by itself. Once you have a baseline for each, you can then figure out where the bottleneck lies. Depending on what the actual bottleneck is, the solution can vary wildly and can be a massive engineering effort depending on the scale at which your application operates at. I recommend reading engineering blog posts from Facebook, Netflix, and other companies dealing with extremely large scales to get a better sense of what goes into solving these type of technical problems.

At the end of the day our number one priority is providing a great experience for our visitors. Our back-end is just one piece of the overall effort that goes into make sure that happens, and when it’s running well, nobody should notice it at all. Kind of like a well-oiled machine running quietly in the background…so cool, so chrome….

]]>
/2015/06/18/performance-optimization-not-premature-optimization/feed/ 0
Aspiring To Code Nirvana Through Tests /2015/02/10/aspiring-to-code-nirvana-through-tests/ /2015/02/10/aspiring-to-code-nirvana-through-tests/#respond Tue, 10 Feb 2015 18:59:12 +0000 /?p=7295 1 + 1 = 2? Obvious right? How about (2 + 2 x 4)^2? That’s a little more complicated but not so bad either. Over our series of blog posts about the Bloomberg Connects project you’ve might been able to tell that testing has been a very integral part of every step of the project. From testing code to testing our assumptions about the way our applications work, testing is what brings us from the darkness of uncertainty to the warmth of enlightenment.

Seated Buddha Shakyamuni, 965-1025. Gilt bronze, 8 1/2 x 7 1/4 x 4 3/4 in. (21.6 x 18.4 x 12.1 cm). Brooklyn Museum, Gift of the Asian Art Council in memory of Mahmood T. Diba; Mary Smith Dorward Fund, 1999.42. Creative Commons-BY Image: overall, 1999.42_SL1.jpg. Brooklyn Museum photograph

Seated Buddha Shakyamuni, 965-1025. Gilt bronze, 8 1/2 x 7 1/4 x 4 3/4 in. (21.6 x 18.4 x 12.1 cm). Brooklyn Museum, Gift of the Asian Art Council in memory of Mahmood T. Diba; Mary Smith Dorward Fund, 1999.42. Creative Commons-BY
Image: overall, 1999.42_SL1.jpg. Brooklyn Museum photograph

As David has mentioned in a previous blog post, we follow a very Agile like process to guide us through our technical development process. One of the most important aspects of this process is writing tests for everything we can possibly write a test for.

What does a typical test look like? Let’s take a look at our earlier example of 1 + 1 = 2. Imagine we have a block of code (we’ll call this a function) that computes the sum of 1 + 1. We know that the sum of 1 + 1 should be 2. Knowing the definition/result of what we’re looking for, we can then construct a test to help us determine whether our function is performing up to standard. This test could simply check that result is two. If we wanted to get more in-depth, we could check that the result is less than 3 and greater than 1.

This is a pretty simple example but sometimes the things we need to test for encompass more than just one isolated block of code but rather how a group of disparate pieces of code work together. When we write tests for the former we call those ‘unit tests’. When we write tests for the latter we call those ‘integration tests’. With a combination of unit tests and integration tests, we can cover most of the different permutations of our use cases.

Jenkins displays a report that lets us know what percentage of our code is covered by tests.  For this particular project it is close to 100% test coverage.

Jenkins displays a report that lets us know what
percentage of our code is covered by tests. For this particular project
it is close to 100% test coverage.

However, even with an extremely comprehensive test suite, this doesn’t prevent bugs from cropping up or other strange errors. Since writing tests is code too and all code needs to be maintained, there arrives a point of diminishing returns for a certain number of tests. After a certain point, a programmer will have a hard time coming up with different permutations to test against due to the inherent complexities in writing software. This isn’t an excuse but rather a reality of projects where the resources of time and money are always a constraint. Sometimes going for the ‘most bang for buck’ tests is the best course of action.

So if writing tests doesn’t ensure bug free code, what do we get from them?

One of the best advantages of writing tests is giving us some level of protection from regressions. As an example, imagine we found a bug in our code. Instead of just fixing the bug and being done with it we also wrote a test covering the newly discovered case the bug presented. Now if for some reason another programmer ever wrote code that reintroduced the same bug, our new test will now catch the error. While this sounds kind of stupid, this can be a fairly common problem due to the sometimes amorphous nature of code.

Another huge advantage of having code tests is that we can now run automated tests. As part of our development process, we use a continuous deployment system that only deploys new code if the new code passes tests. We can also run tests before attempting to push our code live as part of each developer’s own development process. This means we can often times catch issues before they show up in production environments, meaning the end user should typically only see very stable versions of our software being used.

While our current development process has been pretty good, we know that we can always do better. It’s part of our overarching theme of treating everything like an iterative process. As someone famous once said, “if you’re not getting better, you’re getting worse.”

]]>
/2015/02/10/aspiring-to-code-nirvana-through-tests/feed/ 0
Benefitting from Code Prototypes /2015/01/27/benefitting-from-code-prototypes/ /2015/01/27/benefitting-from-code-prototypes/#respond Tue, 27 Jan 2015 16:56:16 +0000 /?p=7268 The dashboard—the web application our audience engagement team will use to answer incoming questions—is a complex application with many parts and before we hit the ground running, I thought it would be prudent to create prototypes.

This decision was informed by the lessons Brian and I learned at General Assembly’s Mobile Prototyping Bootcamp. Though the workshop was centered on mobile apps, we picked up some cross-disciplinary techniques like creating prototypes out of paper and code. We learned that prototypes were a great way to test out an idea without investing too much time and resources to learn if we were correct in our assumptions and to answer any questions we might have about the project’s design. Also with the prototypes we made in the workshop, we had a common language with which we can talk about features and user flows. You would be surprised at how designers and web developers can describe and think of the same action in completely different ways. Prototypes can help bridge disciplines.

As I briefly mentioned in my last post, I created prototypes to evaluate each framework to learn what we were getting into. Two questions I wanted to answer were: “How easy it is use to this framework?” and “Does this framework have everything we need to build the dashboard?” I figured the best way to answer these questions was to use the frameworks to build the same web app and then to compare and contrast.

My approach to creating a prototype was to pick a critical user interface element and to quickly build it out. As I mentioned previously, I picked the chat window.

My goal was to quickly build it out; which meant that I can disregard best practices and settle for an ugly design. A prototype is not meant to be released publicly since the feature being prototyped could be immature or the code could be buggy. It is for demonstration purposes, for “drafting” a feature or for testing an idea. If the chat window was usable, it was a working prototype.

By making a prototype I learned that if we picked Backbone.js, we would have more code to maintain because unlike Angular, Backbone.js is a minimal framework that doesn’t have as many features that Angular has.

After we chose our code framework, I built another prototype, this time using our chosen framework, Angular. In addition to implementing the chat window, I also prototyped the queue and the “research pane,” where hosts could tag conversations with related art objects.

Prototype of our dashboard web application.

Prototype of our dashboard web application.

While visual designs could give us an idea of the look and feel of the dashboard, a working prototype could gives us an idea on how what it would be like to use the dashboard. Visual designs are static while prototypes are interactive; interface elements like buttons and text dialogs are clickable.

Dashboard

The dashboard app in action during a recent user testing session.

A side benefit of making prototypes is that they can serve as documentation that could help us plan and communicate how the dashboard worked. For example, Brian and I were discussing an animation that occurs when a user selects a name. After a user selects a name, a confirmation dialog should pop-up with an animation. I wasn’t too sure what direction he wanted to go in, so I quickly coded a few examples.

Another example is when we were designing the snippet creation flow. Brian had designed the following user experience: The user is presented with a conversation and they are able to select individual messages to create a snippet of that conversation. I wanted to confirm that Brian and I were on the same page in terms where the user was able to click and what would happen after the user clicked a message. You can view this prototype here: http://codepen.io/amycheng/full/cLIBw/.

Visual designs and code prototypes were being created concurrently, which led to one influencing the other. This also prevented designs and code prototypes from going too far in the wrong direction. Working this way helped us answer questions like: Does this user flow make sense? Is the screen too busy? Is this functionality too complicated?

At one point in the project, Brian was in the process of finalizing designs for the activity tab and I was in the middle of building a quick prototype of the activity tab. We discovered that the activity tab, which could potentially contain the conversation queue, a conversation window, and a research pane with any number of related art objects, could look cluttered on narrower computer monitors (Brian was designing on a much wider computer screen than mine). This discovery allowed us to come up with strategies to mitigate the differences between screen sizes.

It was a good idea to create prototypes because it helped us to clarify our thinking about the user experience and code architecture.

]]>
/2015/01/27/benefitting-from-code-prototypes/feed/ 0
Fighting Code Chaos with the Right Framework /2014/12/16/fighting-code-chaos-with-the-right-framework/ /2014/12/16/fighting-code-chaos-with-the-right-framework/#respond Tue, 16 Dec 2014 21:26:43 +0000 /?p=7234 From the outset we knew that the dashboard—the web application our audience engagement team will use to answer incoming questions—was going to be a huge undertaking and we knew we had to lay solid foundation for app development. Since we were doing agile development and designing the app based on user testing, the feature list of the dashboard would likely not be set in stone.

For the dashboard, we had to develop it in a timely manner and still be able to make changes to the codebase without breaking it (think Jenga). Also, we wanted the app to be easy to maintain over time, since it would be a web app that we would be using for years. The best case scenario is an app that was coded in such a way that it is quick to build, is easy to maintain and is easy to adapt to any unforeseen needs. The worse case scenario is unruly legacy code—codebase that degrades over time—and spaghetti code—a disorganized code base.

Legacy code degrades because people forget how to use the code. This could be due to the lack of documentation about the code base or obtuse application architecture. With spaghetti code, it becomes more of a chore to find the causes of bugs and implementing a new feature becomes more involved and troublesome, since introducing a new part into a disorganized system might cause problems with existing parts of that system. Spaghetti code inevitably leads to legacy code.

There are a few ways to mitigate legacy and spaghetti code. There could be a dedicated effort to write good code documentation and to establish a logical app architecture. We pledged to ourselves to do those things, but also thought it be a good (and a smart idea) to use a framework (in the case of the dashboard, a Javascript framework). Coding frameworks provide guidelines and conventions for how code is structured and organized.

Avoiding the mess of legacy and spaghetti code by leveraging frameworks in developing our  dashboard—the web application our audience engagement team will use to answer incoming questions.

Avoiding the mess of legacy and spaghetti code by leveraging frameworks in developing our dashboard—the web application our audience engagement team will use to answer incoming questions.

Using a framework is an easier way for a team to provide organization to their codebase. In addition to a kind of application blueprint, some frameworks also provide abstractions and functions for common development tasks (ie. communicating with an API, implementing animations, data modeling, rendering data to the user). Developers will not have to start from scratch and write their own, idiosyncratic functions for common tasks. Instead, team members would be using the same library of methods and variables. Some frameworks (especially free, open-source ones) also have large communities of developers supporting each other in using that framework. Using a framework, would allow us to draw upon that community as a resource.

It seems like every day there is a new JavaScript framework popping up, but I focused our search to two frameworks: Backbone.js and Angular.js. I chose to look at those two because both frameworks are being used in live web apps by large web companies. Both have good documentation (which makes the framework easy to learn) and large communities.

The way I judged Backbone and Angular was by building a quick and dirty prototype in each. I chose to build a feature that we knew would be in the final version of the dashboard app: a chat window. This chat window allows the user of dashboard to choose a visitor who is waiting in a queue. Then the user of the dashboard can continue the conversation with the visitor. After building the same feature in both frameworks, we decided that Angular was best suited to our needs.

Angular has been criticized for being “highly opinionated,” which means that the framework has a strict application blueprint. For us, Angular having opinions and conventions for application structure meant that we can build something really quickly because we did not have to spend too much time in the planning stages. Angular’s guidelines for building a web app were strict, but not too rigid. Angular strongly encourages developers to write modular code, which means pieces of code can be re-usuable and dropped in when its needed. Every kind of function and variable has its place, which helps with fighting spaghetti code.

Angular also includes a large library of functions for a lot of tasks that we hope to accomplish with the Dashboard app. Tasks like animating user interface elements and interacting with our custom API. With Backbone, we would have had to write a decent amount of boilerplate code (that will likely become legacy code). With Angular, developers won’t have to spend time re-inventing the wheel and they won’t have to spend time re-learning how and why their team mates wrote a certain function.

In addition, unit and integration testing are core features in Angular. Unit and integration testing ensures that any feature implemented in the future does not break existing features. Tests are actually bits of code that makes sure other bits of code are working properly. Angular makes writing tests easier, which makes it more likely for developers to write them (thus preventing legacy code). Tests can also serve as documentation on how the code base works.

Using a framework does not guarantee completely against legacy and spaghetti code, but they can provide a strong foundation for building large apps, like our dashboard.

]]>
/2014/12/16/fighting-code-chaos-with-the-right-framework/feed/ 0
BklynFlow on GitHub /2010/10/14/bklynflow-on-github/ /2010/10/14/bklynflow-on-github/#comments Thu, 14 Oct 2010 18:50:06 +0000 /bloggers/2010/10/14/bklynflow-on-github/ The essential experience of Wikipedia is, for me, one of deep focus without effort — of getting lost in thought without feeling like I’m really getting lost. I think this is one of the most compelling and profound user experiences on the web. To read Wikipedia is to stroll casually from article to article, from place to place, in a way which makes it clear that relationships between things are as important as the things themselves. In the gallery, this means visitors not only learn about the historical context of the artwork on view, but also see how the history of the art is all mixed up with the history of everything else. From a user experience perspective, our challenge was to balance focus with discovery; to let users delve deep into the connections between things, but to always give them a way back home to the artworks themselves.

We wanted to provide a way of reading Wikipedia that could be passed from person to person without anybody getting really lost. A big problem with mouse- and keyboard-based interactive kiosks is that sitting down at a computer can create a situation where one person is in charge of what happens and everybody else is just along for the ride. This is a serious problem when it comes to engaging groups of users; one can’t just pass a mouse and keyboard around from person to person. Hand-held touch devices like the iPad do a lot to get around this problem. They can move from person to person, and they make being a backseat driver a lot more fun. We settled on the idea of a sliding frame with buttons for each artist which, when tapped, would load the Wikipedia article for that artist in a content frame above.

bklynflow_wikipop.jpg

To minimize distraction and maximize fun, we also decided we needed preserve the feeling of using a native iPad application. To this end, we built our first open source software release: BklynFlow. BklynFlow is a MooTools class for creating Coverflow-like user interfaces for the web. It’s easy to use (check out BklynFlow on GitHub for an example), and has has several features that we hope make it particularly appealing: thumbnails can have captions, it supports both touch and mouse interaction, and click/tap behavior isn’t prescribed ahead of time — a click or tap can call any JavaScript function.

bklynflow.jpg

BklynFlow makes use of hardware accelerated 3D transforms, so right now it only works in Safari and Mobile Safari. It was in large part inspired by Zflow. Please let us know what you think!

This post is part of a three-part series on Wikipop.

]]>
/2010/10/14/bklynflow-on-github/feed/ 2