Wednesday, April 26, 2017

Removing Dead Code


Last week I was working on code coverage.  One of the results I saw is that some of the source code we own is not used by any of our testing - it is 0% covered.  Digging into this, I found out that this code is not used at all by Tableau so I intend to start removing it from our codebase.

Code that is not used by the product you are working on is often referred to as  "dead code" and there are a few ways this can happen.  One obvious way is that existing code functionality simply gets provided by something else.  Let's say you had a very slow Bubble Sort routine to sort a list.  Once you learn a faster algorithm to sort, like Quick Sort, you start using the Quick Sort instead.  If you are not diligent when making the code change to use Quick Sort, the Bubble Sort code can get left behind.  It is not used at this point and becomes "dead code."

Similarly, if you need to implement sorting, you could try Quick Sort, Insertion Sort and Merge Sort (for instance).  Once you profile the time spent by each routine and generate the test data, you can make a decision about which routine to use.  Again, if you don't remove the routines you don't use, they become "dead code." 

After digging into the code coverage numbers, I found a few instances of the second case.  Since this code is not used at all, it doesn't get compiled so that helps mitigate having it around.  But it still results in a good amount of unneeded code stored on everyone's hard drive, maintained in our repository and so on.  The best practice is to just get rid of it and that is what I am working on now.

Questions, comments, concerns and criticisms always welcome,
John

Wednesday, April 19, 2017

Working on a code coverage task this week


For this week I am focused on getting code coverage numbers for our team.

Challenge #1 is pretty simple to state - get a list of all the source files that our team owns.  And while the problem is easy to understand, the real world implications of this are a bit trickier, especially with older files we have.  As the years have gone by, ownership of unchanging source files gets a little fuzzy.  The team (or developer) who created the original source file may be long gone.  Even teams that own a file might have been reorganized - several times over - since the file was checked in. 

So if Carol created the original "stats.cpp" file she may be the only person to ever have edited it.  If she moves to another team, and her old team gets reorganized, ownership can get moved to the bottom of the list of problems to address at that point.  After all, if the code is stable, why spend resources on tracking who should be associated with it? 

But after a while, every company has this challenge.  That is what I am sorting out this week.

Fortunately, Tableau has been pretty good with naming conventions for source files.  For example, all Cluster related files have the text "cluster" in them.  For most of the features my team owns, I can simply search by file name to get a good starting point for the files we own.  Getting that list together, parsed and cleaned up is my goal for the week.

After that, I think I may need to move to class based ownership.  More on that next time.


Questions, comments, concerns and criticisms always welcome,
John

Tuesday, April 11, 2017

A nifty site to see what a compiler does to C++ code


While investigating a very intermittent unit test failure this week, I noticed an anomaly in our code.  This test is written in c++ and had an extra semicolon in it:

We had a test that did something like this:
Worksheet wb = wbc->GetSheet();
    ;
 CPPUNIT_ASSERT(blah blah);

Notice that extra ; in the middle?  Since the test intermittently fails, I was looking for anything unexpected in the code.  This is unexpected, but I also needed to know if it was important.

Matt Godbolt created a terrific site that lets you put in C++ code and see what output various compilers produce.  The site is here  https://gcc.godbolt.org/

You can choose different compilers and I just took a look at gcc 6.3 to see if it would ignore an extra ;. 

Here's my test code:
void test()
{
int x=1;
;
}

And here is the output:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 1
        nop
        pop     rbp
        ret

I get the same output with or without the extra semicolon. This is great since I would expect the compiler to get rid of blank commands like this.  Since the compiler does indeed ignore this typo in the code, I can move on to other avenues of investigation.

Give this site a whirl.  You can choose several different compilers and chip options, pass parameters in and so on.  Thanks Matt!

Questions, comments, concerns and criticisms always welcome,
John

Friday, April 7, 2017

Always learning


One of the most fun aspects (to me) of being in the world of software development is the focus on continual learning.  The systems on which we work are constantly evolving.

For instance, when I started way back in 1995, Windows 3.1 was the dominant OS.  Smart phones did not exist, tablets were only on Star Trek and so on.  The challenge is how to adapt to a constantly changing world.

The strategy I use is one of constant learning.  MOOCs have made this much easier in the last few years - I tend to prefer a combination of lectures and hands on to learn a new skill.  To me, which new skill to learn is not as important as always learning something.  Sometimes there is a skill I need to learn that is very relevant to some project that is upcoming - for instance, learning Python because our automation system here at Tableau uses Python is an obvious example.

But other times I take on tasks that are more in a hobby space.  To this end, for the past few months I have been enrolled in a Programming the Internet of Things program at Coursera.  It has been a blast!  It made me brush up on electronics I learned years ago in the navy as well as some programming in C and Python.  I got to work with the Raspberry Pi and Arduino, install some useful libraries and my final capstone was a device that would email me if I left my garage door in my house was left open.  This was a beginner level class so the introduction was very gentle and definitely left me wanting more.

I received my final certificate this last week and am thinking about going deeper into another class.  Either that or finish the growing list of project ideas I developed while taking this class.  Either way, it should be fun!

Questions, comments, concerns and criticisms always welcome,
John

Thursday, March 30, 2017

Some simple data munging work this week


A task I had to deal with this week was this one.  I was given a data set we want to test, like this:
2 3 4 4 5 5 6 6 7 9
We have an algorithm to compute some basic statistics on any given data set (mean, median, variance, etc…).  Nothing special about that.  And I had two data sets - the small one above, used mostly to make sure the testing code would work, and another data set of 50,000+ floating point numbers:
-8322.458 -6199.002 -6002.999 and so on.

What I needed to do was compare the results of those types of calculations across a variety of different tools which also compute those basic stats.  I chose Excel, R, some Python code I wrote myself, Numpy/Scipy and Octave.

And that is where the problems came in.

My original data sets were simply a list of numbers, without commas, seperated by spaces, all on one row.  For the small data set, for all the tools, I could just copy/paste or even retype to get the data into the format the tool wanted.  This is not a hard problem to solve, just tedious.  The industry calls this "data munging" (getting the data from the format you have into the format your tools needs) and is almost always the most time consuming part of any analysis.  Hit me up for links to prove this if you want.

For instance, excel prefers a single column to make entering the calculations easy, but can use a row.  Python's read csv files wants commas to separate values along a row (you can specify spaces) but once the data is imported, it is easiest to have one column of data.  So I had to create a file of the 50,000+ values with each value on one line.

R was able to use the same file as Python.  Nice!

Octave  wanted all the values on one row so I had to re-layout the numbers with a comma in between each.  Since this was a one-off task, I simply used Word to edit the file.  It took a little under a minute to make the 50,000+ replacements.

Now I have the data files in the format that all the tools want, and can use their results to help ensure Tableau is getting expected answers for these basic statistics.

Questions, comments, concerns and criticisms always welcome,
John



Monday, March 27, 2017

Getting our automation to 100%


One of the challenges we have taken on since last year has been driving our test passes to be 100% automated.  Historically, a test pass has had a manual testing component - a human sits in front of a computer that is running a build of Tableau that we intend to ship to customers and validates the responses to test cases are the results we expect.  This can be a challenge because, as often happens, the manual testing phase can take more than a day.  If we get a new build of Tableau each day - and we can get them more often than that - it is possible that we can never finish a manual test pass. 

It also can become very difficult to predict when a manual test pass will conclude.  If there are changes, test will need to validate if the change was expected or not, and while that may be obvious in some cases, it is not always the case.  Imagine that a new piece of hardware, such as a very high resolution monitor, comes out the day before the test pass.  It could be the case that no one on the team knew this would happen and no one has planned for how Tableau should work in that case.  This can slow down the evaluation of the results of the test pass.

To get around this, we embarked on getting enough automation in place that we can avoid all manual testing when a new build of Tableau is released for testing.  For us, this just means looking at automation results and verifying that no tests are failing.  That is my definition of 100% - that we can make our decision based on automation results.  That was a lot of work to get here, and even more work to remain at this level, but it does make testing much more reliable and predictable as time goes by. 

This also speeds up the new monitor test example I gave above.  At this point, all the test results are available so the extent of the test pass is done "all at once."  There is no  back and forth with trying each feature one at a time on the new monitor - all the automation runs and gives a report to the humans that can now start making decisions.  Without the automation, the decision process is slowed down by data gathering, and this is where automation can really speed up the cycle.

We did some tasks other than simply adding automation to help us get here and I'll cover those next.

Questions, comments, concerns and criticisms always welcome,
John


Friday, March 24, 2017

Some reading for my team

We are gathering books today that folks on the team have and use.  I made my contribution to the first pile of books:
The bottom most book - Doing Bayesian Data Analysis - is my contribution to the pile.  We actually had a learning group here last summer using that as our text and I really liked the way it was written.  Very useful, tutorial and plenty of examples. 

I also have a copy of the top book - Causality by Judea Pearl.  To me, that is the key attribute of what people want from statistics : did changing THIS cause THAT to happen?  I'm still working my way through it and am probably about 20% done so far.  Much more dense than I expected, but that is just another way of saying it is filled with information.

Books are a great way of continually learning and I will write more about that next.

Questions, comments, concerns and criticisms always welcome,
John