Tuesday, January 24, 2017

Sprint Planning week


We follow an Agile process here at Tableau and one of my roles in that is scrum master.  Those links are pretty good overview sites if this is not familiar to you.  Jump over there and read a little about this if you want.

We follow a 2 week sprint cycle here and this was our planning week.  Nothing too out of the ordinary with this - we decide what work items we will complete in the next 2 weeks, assign out some of them to get started and decide what we will demonstrate  at the end of the cycle.  The hardest part of this is usually deciding what to demo to everyone who is interested.  In this cycle, we want to demo a tool one of the testers wrote that generates random data that follows a desired distribution, and we have some cluster work we also want to show.

For me, the hardest part as scrum master is usually trying to find a room in which to meet :)  We moved into a new building at the beginning of the month so getting a room this time was a bit easier since the rooms are mostly unbooked right now. 

For the next 2 weeks we will work on the items we decided to do, update our progress daily and meet daily at standups.  One new tactic we are trying for standup meetings is to update per project item, rather than by person.  In the past, each person on the team has provided an update for what has happened for that person in the last 24 hours, but we are changing that to be more project based.  So far it is going well.

Again, nothing earth shattering here but I wanted to give a very broad overview into a typical day at Tableau.

Questions, comments, concerns and criticisms always welcome,
John

Monday, January 16, 2017

Not making a change that would have made no sense


Like most applications, Tableau supports several languages.  Here's a quick screenshot of what we currently offer:


No big surprise here: we keep a list of all the text (strings) that we use in our application in a file, and localize (translate) them into each language. 

For instance, we have the color "Blue" in our UI in many places.  In Spanish, that will be "Azul".  So we have a file that has a string number (let’s say "String1447") and that string number points to several translations of "Blue." 

What we try to do - and this is pretty much the standard way of providing multiple language support - is to never refer to the text "blue".  Instead, whenever we want that word to show, we ask for the correct translation of "String1447" - which in English will be "Blue," in Spanish "azul," etc… 

So if I am looking at a color palette on an English machine, when I hover over the Blue color, the UI asks for the English translation of "String1447" and shows me "Blue." 

I was looking through our string table the other day to see if there was any way to make the process of using it more efficient.  One thing that jumped out at me was that we have several different entries for "Blue" (and "Green" and "Brown" and other colors).  That struck me as odd - why do we need to have all these duplicates?  If we just had one string ("String1447") for Blue, we could have smaller files, less build time, less confusion with knowing which string to use and so on.

So my first thought was to remove all the duplicated strings.

When I looked a little deeper though, I noticed that each color palette we have has its own list of colors.  An example would be the Summer palette.  Blue is near the bottom on my machine:

Another instance would be the Tableau 10 colors:



In the strings file, each color palette has its own list of colors.  There are 8 colors listed for Summer and 10 for Tableau 10 which makes sense.  If I am working with the Summer palette, I would naturally want to use a string name of "Summer_Blue" or similar, naturally want to refer to "String_Summer_Blue" or similar.  And if I was working with the Tableau_10 color palette, I would want to use "String_Tableau_10_Blue". 

My original plan was to replace these with something like "String_Just_Blue" (heh) or "String_Blue" and simply use this string everywhere that we need.  But that plan was shelved pretty quickly since it would make our strings table hard to read.  If the list of 10 colors for the "Tableau 10" palette only listed 6 (because of duplicate strings being removed) then everyone would find it confusing.

So my investigation into making files smaller here would have resulted in a system that is more confusing than what we currently have.  So I am not making this change and moving on to other work.

Questions, comments, concerns and criticisms always welcome,
John

Thursday, December 29, 2016

Some code reviews, some testing and a lot of packing to move this week

It's been a different type of week here at Tableau.  Between getting Monday off for Christmas and now Friday we will be out while we move buildings, there have only been three days to get work done.

So here is a just a short list of things I have done as a tester this week:

1. Posted LOTS of small code changes for review.  As part of an efficiency effort, I am removing bits and pieces of dead code that are left around in the codebase.  It is not an especially difficult task, but will help with maintainability over time.  The most challenging aspect of this is not the code changes - it is finding the right set of folks to review the change I am trying to make.  In some cases, this code has been around for many years, and digging through the history of the repository in those cases can be time consuming.  I want to find the original people who checked in the code to validate my removal and easily more than half my time is spent on this one task.

2. I have managed to do some testing as well.  The most frustrating part of this blog is that I seldom can mention what features I am testing since they are in development.  I don't want to mention new features until they are shiping - I certainly don't want to imply we have a feature that appears to be ready to go only to find out there is some core problem with it.  That creates confusion (at best) all around.  But I managed to automate a test that checks for rounding errors and got that running as well as completing some manual testing tasks.  

3. We are moving buildings this weekend, so I have spent some time packing my stuff.  We also have some common areas, like a library, that I helped with as well.  The movers will be in later today and we will be out while they are moving our gear around.  The frustrating part is that our machines will be powered down.  I won't be able to log in remotely to my machine to keep any of the processes flowing, but hey, I'll take the time off and enjoy myself!

So that's it for the short week here at Tableau.  Happy New Year everyone!

Questions, comments, concerns and criticisms always welcome,
John

Monday, December 19, 2016

Well, that saved some time


After getting our unit tests assigned to the correct team, I took a few days off so no post last week.  When I returned, I found a defect assigned to me saying that a unit test was failing.  In this case, the test was related to filling in missing values from a column of data that the user is trying to display in a visualization.  Now, to be fair, there are many different ways to try to infer what the missing data should be and there is a larger question of whether you should impute a missing value at all.  But the purpose of this test was to validate that in a range of numbers with a missing value that if we want to use the average of all the values to fill in a missing value, we would compute the average correctly and actually add it to the column of missing data.

This is not an especially difficult test and the code that it exercises is not all that challenging either.  If you ever take a class in data science this is typically an exercise that you will be asked to complete early in the class cycle.  IIRC, this was near the end of my first "semester" of this online program from Johns Hopkins.  (This was a good class, by the way).  Anyway, I looked at the test and realized this was not my area - a partner team owns that codepath now.  I simply assigned it over to them to investigate the source of the error and moved on to my next task.

My next task is simply TFS - Team Foundation Server - cleanup.  I am our team's scrum master, so one of my duties is to stay on top of incoming defects and help keep our sprint schedule on track.  This doesn't take all that much time, maybe a few hours per week, but being timely makes it much easier than letting the database start to build up.  So I devote a small amount of time each day into scrubbing through it.  After that, I will start digging into our manual test cases to see if automating any of them would be the next best step for me to take.

Questions, comments, concerns and criticisms always welcome,
John

Monday, December 5, 2016

Unit and integration tests


I've been working to assign ownership to the correct team for "unit tests" recently.  While changing the team name that owns each test is straightforward in most cases, in some I had to step into the tests to determine exactly what was being validated.  This is a great way for me to learn the code, by the way.

In any case, I soon discovered that some of the tests I had been thinking about as unit tests are actually integration tests.  The difference between the two is what I want to mention today.

A unit test is the simples form of automated testing that we write.  In a simple case, suppose I am writing a calculator application and want to multiply two whole numbers.  I could write a function that looks something like this:

int multiply(int first, int second)
{
int result = 0;
for (int i=0;i<first;i++)
{
result = result + second;
}

return result;
}

Now when I write a unit test, I can pass in 8 and 4 and validate I get 32 as a result and also 0 and 2 to validate I get 0.  Not much to this but that is the point of a unit test - it tests just one function.  If it fails, I know the exact one function that now needs to be investigated.

Then suppose I add a power function to the calculator.  Raising a number to a power is just multiplying the number by itself as many times as I want the power t be, so my function to this might be:

int power(number, power)
{
If(power<0)
return ERROR_CODE;
int result ;

for (int i=0;i<power;i++)
{
result = multiply(result, 1);
}
return result;
}

I just call my multiply command as part of my power command.  Reusing code is always a goal.

But now when I test my power function, I have a challenge if the test fails.  A failure might be in the part of the code that is unique to my power function, or it could also be in the multiply command.  There could also exist a case in which both tests are failing for different reasons.  So instead of quickly finding the one bit of ode I need to investigate, I now have 2 places to look and three investigations to complete. 

Looking more at the calculator, if I added a "Compute compounded interest function" I would need to use the power function and the multiply function and possibly a few others as well.  Now if a test fails I might have dozens of locations to investigate.

On the positive side, I might also discover a flaw in my code that only shows when one function calls another.  This type of functionality is referred to as an integration test and is absolutely critical to shipping software.    Read about the most famous example of not covering this here: a Mars satellite was lost because Lockheed Martin tested all their code with miles and everyone else tested all their code with kilometers.  Very loosely speaking, the Lockheed code told the spacecraft it was "1,000,000" from earth it meant one million miles.  When the satellite heard "1,000,000" it assumed kilometers and that was the root of the loss of the satellite.  Integration tests should have been use to catch this type of error.

Eagle eyed readers will point out that my power function is useless without the multiply function.  How can I isolate my unit tests to use only the code in that function instead of needing the multiply command as well?  I'll cover that next time up.

Questions, comments, concerns and criticisms always welcome,
John

Monday, November 28, 2016

Cleaning up ownership of some legacy tests


The Statistics team used to be a combined team here at Tableau and was called Statistics and Calculations.  Before I started, there was a small change made to make Statistics its own standalone team.  All has been good since with one small problem - all of the tests the combined team owned are labelled as being owned by "Statistics and Calculations.  When a test fails, the person that notices usually just assigns the test to Statistics (since our name comes first in that string, I guess) even if the functionality being tested is not owned by our team.

An example of a feature we own is Clustering.  We wrote that and own all the tests for it.  An example of a feature we do not own now that we are a standalone team would be table calculations.

Anyway, we have hundreds of tests that need to be retagged.  I decided to take on this work in order to properly tag ownership of the tests.  This way, if a test fails, it can be properly routed to the best owner immediately.  The first challenge is just getting a list of all the files that I need to edit.  The lowly DOS command (DOS?  Isn't that going on 40+ years old?) "findstr" was incredibly useful.  I just looked through every file in our repository to find the old string "Statistics and Calculations" that I need to edit.

Now I had a list of all the files in a weird DOS syntax.  Example:
integration_tests\legacytest\main\db\RegexpMatchFunctionTest.cpp:    CPPUNIT_TEST_SUITE_EX( RegexpMatchFunctionRequiredUnitTest, PRIMARY_TEAM( STATISTICS_AND_CALCULATIONS_TEAM ), SECONDARY_TEAM( VIZQL_TEAM ) );

Also notice that the path is incomplete - it just starts with the \integration_tests folder and goes from there.

The actual list of files is well over a hundred and my next task was to clean up this list.  I though about hand editing the file using Find and Replace and manually cutting out stuff I did not need, but that would have taken me well over an hour or two.  Plus, if I missed a file, I would have to potentially start over, or at least figure out how to restart the process with changes.  Instead, I decided to write a little python utility to read through the file, find the (partial) path and filename and remove everything else in each line.  Then correct the path and add the command I need to actually make the file editable.  Our team uses perforce so this was just adding "p4 edit " to the start of each file.  And fixing the path was pretty simple - just prepend the folder name I was in when I ran findstr.

Finally, clean out duplicate file names and run my code.  It created a 13K batch file ready for me to get to work, and if I need to update, I can just run my code again.  Kind of like reproducible research - at least that is how I think of it.

I can post the code if anyone is  interested, but it is pretty basic stuff.

Questions, comments, concerns and criticisms always welcome,
John

Monday, November 14, 2016

Obligatory Tableau Conference follow up


Tableau Conference 16 (TC16 as we call it) was successfully held last week in Austin, Texas.  Hundreds of talks and trainings, keynotes from Bill Nye and Shankar Vedantam, a look ahead into our plans and thousands of customers made for a  very busy week.  I was there working from Saturday to Thursday and it seems like the time just flew by.  For what it is worth, I took a hiatus from technical work and kept the logo store stocked as well as I could.  While I was able to meet many, many customers in the store, I did not have the time to talk much about Tableau and their usage.  The conference is both a blur and fresh in my mind, if such things are possible, and this is a quick summary of what I remember.  I wanted to focus on users while I was there, so that is what is on my mind today.

On the way home, though, a buddy and I met a couple of Tableau users in the airport.  We started talking about their usage and I asked them if we could do one thing for them, what would it be.  One answer was "add more edit commands to the web UI."  Fair enough.  The other was to help with the classification (or bucketing) of many levels of hierarchical data.  They classify educational institutions broadly - I have in my mind "Liberal Arts School", "Engineering", "Fine Arts" and so on.  Then, they classify each school further into many different levels and they need a tool to help with that.  I also imagine this visually as sort of like a process flow diagram, but that may be off base.

If you attended, feel free to let me know what you thought of the conference.  And if you did not, I would encourage you to go next year.  Biased though I may be, I thought it was informative and fascinating. 

The videos from the sessions are available to attendees here: http://tclive.tableau.com/SignUp if you missed anything (and I missed a whole lot!)

Questions, comments, concerns and criticisms always welcome,
John