Last Wednesday afternoon I anxiously asked my boss for permission to make changes on our application code repository. I said I wanted to try fixing some of the reported bugs listed on our tracking system, if there are no other resources available to pass them to. I made a case about myself not posing any problems because of the code review process built into our repository management tool, that there’s no reason for me to merge any changes without getting feedback from a senior developer first.
He smiled at me and gleefully said “Go ahead. I’m not going to stop you.“, to which I beamed and heartily replied “Thanks, boss!”
This is a turning point in my software testing career, to be able to work on the application code directly as needed. It is actually one of my biggest frustrations – to not be able to find out for myself where the bug lives in the code and fix them if necessary. It’s always a pain to be able to do nothing but wait for a fix, and for a fix to be dependent on the resources available. In my head I think that I’m available and maybe I can do something, but I don’t explicitly have access to the application itself and the code that runs it so I can’t do anything until I have the rights to do so. That’s how it always been. Software testers are often not expected to fiddle with code, at least in my experience, especially in the past where automation was not yet known to be useful as a testing tool. Now that I have the skills and the permission to work on the application repository, I feel that my reach for making an impact on application quality has now expanded remarkably well.
Now bug-fixing is not software testing work in the traditional sense. But I figured there’s no harm in trying to fix bugs and learning the nitty-gritty details of how our legacy applications actually run deep in the code. I believe that learning technical stuff helps me communicate better with programmers. It helps me test applications in a more efficient manner too. Of course I have to consistently remind myself that I am a software-tester-first-programmer-second guy and have to be careful not to fill my days playing with code and forgetting to explore our applications themselves. That said, there are ideas I really want to experiment within our software development process, towards the goal of improving code quality and feedback, and I can only tinker with those ideas inside the application repository itself. Dockerized testing environments, code linting, and unit tests are three things I want to start building for our team, ideas that I consider to be very helpful in writing better code but has not been given enough priority through the years.
I think I’m still testing software, just extending the knowledge and practice of the various ways I perform testing.
One interesting topic I’ve come across this year in a few podcasts I listen to is Stoicism. William Irvine introduced the school of thought in an episode of the Art of Manliness podcast and Ryan Holiday wrote a practical guide about it for entrepreneurs on The Tim Ferriss Show. It has practical applications in daily life, and because of that I’d like to eventually learn more about what to practice and its how’s and why’s. For now though, I thought that reading up on Seneca’s essay ‘On the Shortness of Life‘ would be a good starting point.
Here are some notes from the essay:
- It’s not that we have a short time to live, but that we waste much of it. Life is long enough, and it’s been given to us in generous measure for accomplishing the greatest things, if the whole of it is well invested. But when life is squandered through soft and careless living, and when it’s spent on no worthwhile pursuit, death finally presses and we realize that the life which we didn’t notice passing has passed away. So it is: the life we are given isn’t short but we make it so; we’re not ill provided but we are wasteful of life.
- Look at those whose prosperity draws crowds: they are choked by their own goods. How many have found their wealth a burden! How many are drained of their blood by their eloquence and their daily preoccupation with showing off their abilities! How many are sickly pale from their incessant pleasures! How many are left with no freedom from the multitude of their besieging clients!
- What foolish obliviousness to our mortality to put off wise plans to our fiftieth and sixtieth year, and to want to begin life from a point that few have reached!
- The person who devotes every second of his time to his own needs and who organizes each day as if it were a complete life neither longs for nor is afraid of the next day. For what new kind of pleasure is there that any hour can now bring? Everything has been experienced, everything enjoyed to the full. For the rest, fortune may make arrangements as it wishes; his life has already reached safety. Addition can be made to this life, but nothing taken away from it – and addition made in the way that a man who is already satisfied and full takes a portion of food which he doesn’t crave and yet has room for.
- I am always astonished when I see people requesting the time of others and receiving a most accommodating response from those they approach. Both sides focus on the object of the request, and neither on time itself; it is requested as if it were nothing, granted as if it were nothing. People trifle with the most precious commodity of all; and it escapes their notice because it’s an immaterial thing that doesn’t appear to the eyes, and for that reason it’s valued very cheaply – or rather, it has practically no value at all.
- The greatest waste of life lies in postponement: it robs us of each day in turn, and snatches away the present by promising the future. The greatest impediment to living is expectancy, which relies in tomorrow and wastes today. You map out what is in fortune’s hand but let slip what’s in your own hand. What are you aiming at? What’s your goal? All that’s to come lies in uncertainty: live right now.
- There is a common saying that it was not in our power to choose the parents we were allotted, and that they were given to us by chance; yet we can be born to whomever we wish. There are households of the most distinguished intellects: choose the one into which you’d like to be adopted, and you’ll inherit not just the name but also the actual property, which is not to be hoarded in a miserly or mean spirit: the more people you share it with, the greater it will become.
- Honors, monuments, all that ostentatious ambition has ordered by decree or erected in stone, are soon destroyed: there’s nothing that the long lapse of time doesn’t demolish and transform. But it cannot harm the works consecrated by wisdom: no age will efface them, no age reduce them at all. The next age and each one after that will only enhance the respect in which they are held, since envy focuses on what is close at hand, but we more freely admire things from a distance.
- It is nevertheless better – believe me – to know the balance sheet of one’s own life than that of the public grain supply.
- In this mode of life much that is worth studying awaits you: the love and practice of the virtues, forgetfulness of the passions, knowledge of how to live and to die, and deep repose.
Everyday, prepare a very specific question (or a task) interesting enough to warrant research for an answer within several hours without distraction. Sometimes for learning, sometimes for fun, hopefully most days for both. Everyday there must be an adventure to immerse in, albeit small, something to be curious for.
But there are some other intriguing experiments I’d like to try, some of which are:
Maybe you’d like to test them too. 🙂
Because of a small tool pitch I gave to our technical writer, I had a chance to play with Excel files through code for several hours last week. I have not done that before, but I felt that it was a pretty easy enough challenge as I have worked with CSV files in the past and thought that the experience would be something similar. I knew I just have to find out what existing libraries I could take advantage in order to build what I thought the program should be capable of doing, which is basically reading two Excel files, comparing them, and creating a new file with updated data based on both files.
Some googling brought me to the ruby gems Roo and Write_XLSX.
Roo helped with reading Excel files, and we can do this by:
xlsx = Roo::Spreadsheet.open(FILE_PATH)
xlsx = Roo::Excelx.new(xlsx)
spreadsheet = xlsx.sheet(SHEET_NUMBER)
Once we have access to a desired Excel file, we can get whatever data we need from it:
spreadsheet.each(column_data_1: COLUMN_NAME_1) do |info|
// do something with information
After that, it’s just a matter of what information do we want to retrieve and manipulate from desired files. I mostly like to use arrays and hashes from here on.
As for creating new Excel files, we can use write_xlsx:
workbook = WriteXLSX.new(FILE_PATH)
worksheet = workbook.add_worksheet
worksheet.write(ROW_NUMBER, COLUMN_NUMBER, INFORMATION)
These two libraries can actually do more. Roo has an interesting read/write access with Google spreadsheets using roo-google. Write_XLSX on the other hand have formatting features we can leverage for better looking Excel outputs. I didn’t have to use those functionalies for the current test project though so I’ll leave those for another time.
Last week I told our technical writer, a music expert, a video games enthusiast, a good father to his young daughter, and a loving husband to his wife, that I could build him a small tool that could quickly update a master file of local translations, so he could focus his precious time on more important matters other than the job of laboriously cross-referencing and manually updating such a document. That was a passing comment while some of us were suddenly randomly discussing the process of how he was currently maintaining the file. However, the passing comment also felt like a pitch to a software development project that had some sort of value to a very specific customer, and an easy one at that. It was a fascinating experience; it makes you think about how caring for the well-being of someone is very much a part of building software of value, and that good software connects people for the better.
Let’s see how that tool works out this week.
I’m currently in the midst of a test code overhaul, a re-writing project of sorts. It started about a week ago and so far I’ve made considerable progress on what I’ve wanted to achieve with the rewrite, which is basically cleaner and more maintainable code, mostly in the sense of test data management and test description language. The number of tests running everyday in our Jenkins system has grown noticeably and I’ve felt that it’s been difficult to add certain tests because of how I structured the test data in the past, which I have not upgraded since then. The two possible avenues for running tests – on the UI and HTTP layers – also adds a bit of complexity and it’d be nice if I can integrate the two smoothly. It’s an interesting development because I did not plan on any re-writing to be done anytime soon but I guess at the back of my mind I knew it’ll happen eventually. And so I decided to take a step back from writing more tests and do some cleanup before it gets tougher to change things. I plan to finish everything in about a month or so.
At the moment, I’m reminded of the phases I’ve gone through in learning to code and writing automated checks in the past few years:
- Early 2014. It all begins with Selenium IDE, with giving the self some time to study the basic Selenese commands for writing automated checks and (more importantly) understand how to properly retrieve the page elements you want to manipulate.
- Mid 2014. Test management in Selenium IDE becomes difficult as the number of tests grow, hence the decision to switch to Selenium WebDriver. The only programming language background I had back then was C++, which was limited to only functions and logical/conditional operators, so I chose Java to work with to lessen the learning curve.
- Late 2014. Familiarized myself with Git, which hooked me on making daily commits and appreciating version control. Along the way I learned the concepts of classes and objects.
- All of 2015 up to Early 2016. I was in a trance, writing code daily and pushing myself to create all the automated checks that I wanted to run for our apps before every release. Tests run on the Eclipse IDE using TestNG and I was happy with what I had, except that those end-to-end tests are really slow. Running everything took overnight to finish, which was okay for my employer but annoying for me personally.
- Mid 2016. Re-writing existing tests in Ruby with Cucumber integration started off (when I found Jeff Morgan’s “Cucumber & Cheese” book online) as a side project for fun and testing my skill level in programming. And I did have buckets of fun! The experiment told me that there’s still a lot I need to practice on if I want to write better code, and it also told me that I can be more productive if I switch programming languages. There’s a bit less code to type in when writing code in Ruby than Java and I liked that, plus all the interesting libraries I can use. I switched to Sublime Text and used both Jenkins and the command-line interface more extensively too.
- Late 2016. As I was looking for ways to speed up end-to-end tests total execution, which by then takes about 4 hours to complete, I ended up exploring testing apps in the HTTP layer instead of in the UI. That took a lot of studying of how our apps actually behave under the hood, what data are being passed around, how images are actually sent, how to view pages without a browser, how redirections work, among other things. After years of testing apps via the user interface, this was such a refreshing and valuable period, and I completely wondered why I never knew such a thing existed until then. It wasn’t being taught extensively to testers, perhaps because it all depends on how the app was structured to run through an API.
And these phases brings me to now, where there’s a healthy dose of API and UI layer tests all checking major app features. It’s all good, just several pieces needing a cleanup, a little parallelization, better test description language, and great documentation. It’s all good, because the lessons in both programming and testing keep piling. The two practices differ in mindset but I think they complement each other, and I think that there’s no reason anyone can’t do both.