Handy tips for software support

One thing I did not realize when I started my career as a software engineer was how much time would be spent investigating issues and fixing bugs. At my current company, my teammates and I take turns being the point-person for production issues and support tickets; it’s not my favorite shift, but it needs to be done.

Being responsible for several issues and bugs can be quite overwhelming, especially if you bounce between several support tickets multiple times a day. Over the past few years, I’ve adopted several practices that I’ve found helpful, and maybe they can help you too!

1. Be organized

It sounds obvious, but organization is can drastically improve your efficiency as a programmer. When returning to work on a ticket in the morning or after a weekend or after working on something else, we want to spend less time asking “what was this all about again?” or “how far along was I in this?” and more time fixing the problem. Here’s how I like to stay organized.

Folder

I like to have a folder that contains a folder for each ticket I’m dealing with that shift. Each folder is labeled with the ticket number and a brief description (usually the title of the ticket). In each folder, I keep any data files that I may have copied from one of our file servers. If I have taken any notes that don’t need to shared on the ticket itself, I’ll keep those here too. Lastly, I keep a SQL file here (more on that later).

Folder Screenshot

An extra note about files: if you are investigating a data issue and you have a set of files that have good data and some that have bad, clearly label them GOOD and BAD. It sounds obvious, but I’ve only just started doing this, and it really helps. The less you have to access the hard-drive that is your long term memory, the faster you work. More significantly, there’s nothing worse than scrutinizing a file thinking it’s a bad file when, in fact, it is not.

Bookmarks

Similar to our filesystem folder, it is good to have a clearly labeled bookmark folder that has bookmarks to any and all pages relevant to the ticket. Links to reading material, Stack Overflow questions, and documentation are all valuable items to preserve. If you are working on a web application, bookmarks to the pagesof issue are very handy as well.

Bookmark Screenshot

SQL

Lastly, I like to have a SQL file that contains any queries that I use in my investigation of the ticket. Personally, this has been the most helpful practice of all. When jumping back and forth between tickets, I found that I was having to recreate certain queries each time to catch up to where I was before. This is an absolute waste of time. If you have any queries that aren’t obvious in their function, slap a comment on them; you may remember what they do now, but you might not after a long weekend.

2. Be humble

Ask for help

You want to find an optimal balance between asking for help and figuring it out yourself. In my experience, that balance is found in asking for help more often than not. What I mean by “asking for help” is not asking someone to solve your problems, but rather to point you in the right direction. If you are afraid that you are bothering your teammates, remember, it’s better to spend 15 minutes of both of your time figuring something out than you banging your head against that problem for an hour. If your teammates have been in the game for awhile, I’m sure they understand this.

Your fellow engineers aren’t the only people who can help you in fixing issues. If the issue was reported by technical support or customer representative; make sure to chat with them about anything ambiguous or unclear in the ticket. Avoid wasting time solving the wrong problems.

Don’t be arrogant, just don’t

If a client is reporting behavior in your application as a bug or issue, and tech support sends it up to you, but it turns out the application is working as intended, or the issue is due to customer error; be gracious in your response.

  1. Don’t make the tech support person or client feel dumb for not realizing this.
  2. Do use this as an opportunity to reevalute your application to see if there are ways to prevent this issue from happening again.
  3. Seriously, be kind. It goes a long way.

3. Be helpful

Work with your support team

If you aren’t interfacing with customers directly, someone else is, and they are probably the person who reported the ticket. Be conscious of the pressure this position can bring. Be quick in your first reponse to a ticket; if there’s any information you can give immediately, provide that as soon as you can. Also, keep them posted on any updates; you don’t want your customers to feel like you aren’t working on their issue. Furthermore, if there is a tech support / customer support manager, talk to him or her to see if they have a priority list of which issues should be addressed first. It can be tempting to work on issues that appeal to you, but that is not helpful for your team. Trust your support teams to accurately gauge the feelings of the customer.

Lend a hand to your fellow engineers

In larger engineer teams, it’s hard to know the ins and outs of every software component. When you are done investigating and resolving an issue, document it. If you found yourself debugging an poorly documented system, fix that! Don’t let the next developer have to go through the same thing as you. You can both document this in a permanent place where your teammates can easily find it, but also I’d encourage just sending a message to your teammates saying something along the lines of “Hey all, I just was investigating x and found out y and z, let me know if you’d like to hear more about it.”

Okay, that’s all I got. I hope you find at least some of this helpful. Now go put out those fires!

How's your Omnibox game?

If you are developer in 20178 chances are, if you are on your computer, you have a web browser open. And according to this, there’s over a 60% chance that it’s Chrome. If so, this is for you.

By now, many of you know that you can set up custom search engines to use in Chrome’s Omnibox, they’re super handy. If you know how to set one up, skip down a paragraph; if not, here’s how: In Chrome, go to Settings > Manage search engines. Here you can define custom search engines that have three properties: a name, an alias, and a URL. For example, I have a custom search engine called Wikipedia, with an alias wiki, and http://en.wikipedia.org/w/index.php?title=Special:Search&search=%s as the url. The %s will be replaced by the search string. If I want to search Wikipedia, all I have to do is, in the Omnibox, type wiki (space or tab) and then the search string (whatever I want to search for), and bam, it is searched.

Now, being able to search websites easily through the Omnibox is well and good, but let’s try thinking outside of the (Omni)box. I will share with you some of my favorite custom search engines, and why they are great (or at least neat).

In order from neat to necessary:

5. Translate (for me, English to Spanish)

URL: https://translate.google.com/?source=osdd#en/es/%s

Where en is the “from” language, and es is the “to” language. I would rank this higher if I used it more, but still, handy in a pinch! I’m sure you could do the same with another translating service.

4. Thesaurus/Dictionary

Thesaurus URL: http://www.thesaurus.com/browse/%s?s=t
Dictionary URL: https://www.merriam-webster.com/dictionary/%s

Obviously, use whatever dictionary website you want. Once I set up the thesaurus search engine, I find that I use it a surprising amount! And now I write illustriously.

I use a lot Atlassian products, like Jira and Confluence, and I’ve set up a custom search engine for Confluence, and one search engine for each Jira board I’m interested in. If you or your company has some sort of intranet site or wiki or online documentation, a custom search engine works like a charm.

2. Maps

URL: https://www.google.com/maps/search/%s

I use maps as the alias, so I can type “maps Chipotle” and will immediately be shown the nearest Chipotles, which is cool, but we can take it a step further. I can also type “maps here to Chipotle” and I will be given directions to the nearest Chipotle. Technology at it’s finest. Furthermore, if you have your home or work location set with Google Maps, you can type things like “maps work to Chipotle” and be given directions for that.

1. Gifs

Google URL: https://www.google.com/search?q=%s&tbm=isch&tbs=itp:animated
Giphy URL: https://giphy.com/search/%s

You want to be the fastest gif in the West? This is how. Call me old-fashioned, but I prefer Google’s animated image search over Giphy, especially at work. I mean, the last thing I want is a bunch of flashing colors and images on my screen to draw attention to the fact that I’m looking for a gif.

Honorable Mentions

Amazon, YouTube, Google Calendar, Bible Gateway, Spotify

Happy searching in a customized way!

A fresh coat of paint

My wife and I recently painted several rooms in our house. The old colors were from the previous owners and we wanted to make the house more our own. It really is surprising how much a new wall color can change the overall vibe of a room. It’s quite refreshing and brings a new life to the space.

Similarly, I have now been working at my current company for a little more than four months; and up until recently, had been using the default fonts and colors for Visual Studio. But a couple weeks ago I switched from a light theme to a dark theme, hand selected a few colors for major text editor elements (like keywords, comments , and literals), and switched the font to Inconsolata.

All these changes are very superficial, but they helped usher in a new energy when coding. Furthermore, it encouraged me to treat my code as an art: visually pleasing, easy to read and understand, and structurally consistent.

If you feel like your maybe in a rut with coding, try shaking things up a little. Small changes can help add some excitement from what can easily become a daily grind.

Memoization in the wild

TL;DR: Memoization isn’t just for fibonacci numbers.

Time-weighted returns

Let’s consider a portfolio’s time-weighted return, or TWR. Each day the value of a portfolio can either rise or drop a certain percentage. Now, let’s say you have a list of the daily returns since the inception of the portfolio and you want to find out what the portfolio’s returns over several date-ranges are. Most likely you’ll want to know the daily return, the week-to-date return, month-to-date return, and so on, up to the inception-to-date return.

To calculate the time-weighted return from inception to a certain end-date, one would need to do the following:

Rtwr = ((1+R1) x … x (1+Rn)) - 1

where R1 is the daily return after the inception date, and Rn is end-date’s daily return. So we have to iterate over this list of daily returns multiple times in order to calculate all our returns, right? No. You see, the above formula doesn’t just work for daily returns, but rather returns over any arbitrary, consecutive periods. So if you have a return for the month of April and one for the month of May, you could do the following:

Rtwr = ((1+Rapr) x (1+Rmay)) - 1

and you would end up with the return over both months. You see where I’m going with this?

Devising our plan

First things first, we need to get our dates straight. We need our end-date that we are getting returns for, we need the inception date, the last day of the previous year/quarter/month/week (in regards to the end-date), and the day before the end-date. We’ll call these dates our breakpoints.

Okay, so we will store our daily returns in an array, sorted by date, ascending. We will translate our date breakpoints into indexes into that array by subtracting the inception date from those dates.

We’ll have a function GetReturnOverDates(startDate, endDate) that calculates the total return from startDate to endDate. Now this is where the memoization comes in. The first thing GetReturnOverDates does is check a map to see if this date range has already had a return calculated for it; if it does, it returns that. It then iterates from startDate to endDate, adding each daily return to the formula at the top. Once we iterate to a breakpoint, we then call GetReturnOverDates(breakpoint, endDate) and add that to our formula. Essentially making the formula:

Rtwr = ((1+RstartDate) x … x (1+Rbreakpoint) x Rtrw2) - 1

where Rtwr2 is the result of GetReturnOverDates(breakpoint, endDate).

The payoff

So, lets say we already calculated the daily and week-to-date return and we want to get the month-to-date return. We start by calling GetReturnOverDates. It will iterate from the last day of the previous month until it hits a breakpoint, which will most likely be the last day of the previous week (if we aren’t in the first week of the month). It will then call GetReturnOverDates(breakpoint, endDate) and that call will find that we already calculated that return and won’t have to do any more calculations! We then keep doing this for quarter-to-date, year-to-date, and finally, inception-to-date, all without iterating over the same daily return more than once!

Closing thoughts

It should be noted that if the inception date is more than a year prior to the end-date, its return is probably most useful if it is annualized. This doesn’t really change our method above, it just tacks on an extra calculation at the end.

It's the little things

It has been a little while since I’ve last worked on my little Android weather app, so I wanted to get back into it with a small, simple task. So, I decided to replace the text that describes the weather with little icons. Like so:

UI Screenshot

I did some StackOverflow searching to see how people map text to image resources. I found a reasonable solution here. However, instead of hardcoding the “format string” I added it to strings.xml. Furthermore, there isn’t a one-to-one mapping from condition strings and icons. Consequently, I made a new resource file to map the formatted condition string to the actual drawable resource. A snippet of it here:

 
<item name="ic_flurries" type="drawable">@drawable/ic_weather_snow</item>
<item name="ic_fog" type="drawable">@drawable/ic_weather_cloud</item>
<item name="ic_hazy" type="drawable">@drawable/ic_weather_cloud</item>

I don’t have an icon for fog or haze, so I’m just using the cloud one for both. What my code ends up looking like then is:

Integer resourceId = getResources().getIdentifier(icon_str, "drawable", getActivity().getPackageName()); iconView.setImageResource(resourceId); 

Notes from this experience:

  • I need to hook up a keyboard shortcut for recording keyboard macros in Android Studio
  • I still think there’s a better way to map these string values to the resource id. Maybe in a db?
  • Android layouts still don’t make a ton of sense to me; I had to fuss a lot to rearrange the Views to be positioned how I wanted.

It really was such a small change, but I definitely appreciate how much better it looks now.

Icons made by Freepik from Flaticon is licensed by CC 3.0 BY

Two things

Comments on Comments

Check out this post by Andreas Klinger about comments, titled “Good comments explain WHY, not WHAT, and 3 more rules on writing good comments.”

While you wrote the code it was obvious to you - it will never be that obvious again - to no-one, including you.

So true. Even if you work primarily on your own, well written comments can save you from having to mental time travel later on. I’m definitely going to try to write better, less redundant comments from now on.

dev.to

I found this post on dev.to, which has been described as Medium for developers. I would describe it as more personal, community-focused HN. But anyways, I just found out about this place the other day (on HN, I think…), and I really like it! The posts I see on here, while very informational, are also quite personable. Check it out!

An almost useful Android app

Okay, so a lot has been accomplished since my last post. I’m not as interested in getting into it, but my little Go service (which I refer to as GoWeather) now provides an hourly forecast instead of just the temperature. But most of my work has been on the Android app.

Laying out layouts

The first thing I did was drastically change the layout of the MainActivity. Now it won’t look very different to the user at this point, but behind the curtain there is much more flexibility.

UI Screenshot 1

The main layout for the activity is now just a container where I can place fragments. The current fragment will be chosen by using the sliding navigation menu seen below.

UI Screenshot 2

The Cities option seen in the menu is next on my todo list. Currently, the app gets forecasts for a hardcoded city. The Cities fragment will be used to manage the user’s saved locations. By default, the app will show the forecast for the user’s primary city.

Volley and Gson

In my previous post, I was using an AsyncTask and a JSONReader to read the temperature from the GoWeather API. Now that I want to get a little more out my service, I am utilizing a couple solid libraries to not only save myself some work, but also to hopefully contribute to the robustness of my app (which is currently at zero). Volley is a networking library, and Gson is for JSON-Java serializing/deserializing. You can read a great intro tutorial by Kyle Banks concerning the both of them here.

What’s next

  • The Cities manager that I described earlier
  • Icons instead of text for displaying the weather condition (overcast, etc)
  • I started working on saving data to be persisted between reconfigurations, but it isn’t working, so, yeah
  • Allow flipping between Fahrenheit and Celsius
  • Much, much more

You can see the repository for the GoWeatherApp here and GoWeather here.

A sub-minimum viable Android app

In my last post, I set up a minimal (and I mean minimal) backend server. All it does is provide the temperature for a given city. I actually went ahead and set up this little Go server on Heroku; I just like having things running in production, no matter how insignificant they may be.

Anyways, what good is a service if nothing is using it, right? On that note, today I’d like to make a little Android app to utilize the server and display the temperature. At this point, I would say I am familiar with Android development, I haven’t made anything, but have dug around some code and checked things out. So, I think this will be an enjoyable learning experience. So, let’s get started!

The user interface

I’m a sucker for making user interfaces. I enjoy the psychology that’s involved, and I’m just a big fan of stuff looking pretty. Now, just because I enjoy all that, doesn’t mean I’m good at it. Here’s what I whipped up in Android Studio:

UI Screenshot

Yeah, not pretty. Nor really functional. But let’s make it work first, and then we’ll see about making it more useable.

As a prototype, the use case is this: user enters a zip code and presses “Get Weather” and then the temperature for that zip shows up in center. That’s it.

AsyncTask

private class GetWeatherTask extends AsyncTask<String, Void, Forecast> {
  @Override
  protected Forecast doInBackground(String... zips) {
    try {
	  return getForecast(zips[0]);
    } catch (IOException e) {
	  return new Forecast();
    }
  }

  @Override
  protected void onPostExecute(Forecast result) {
    TextView textView = (TextView) findViewById(R.id.temp_text_view);
	textView.setText(String.format(
	  getString(R.string.temperature_display), result.getTemperature()));
  }
}

This GetWeatherTask thread is started if the zip code is deemed valid after the button is pressed. I won’t even bother showing you getForecast because it just makes an HttpsURLConnection and then reads the JSON from my Go server using a JSONReader, and frankly, it’s uninteresting. Ultimately, it’s going to be tossed and redone anyways.

Until next time, I’m going to be working to make this into an app that someone would actually maybe want to use.

Getting started with Go

For the past few years I have been employed as a Delphi developer for an investment company. I started this job right out of college, where I majored in CS. I always knew I would want to branch out at some point, well aware that Delphi isn’t the future. Today, I’m getting started. Getting started with Go.

At this point I’ve done a little reading, just to get primed. Here are the few resources I’ve used:

But that’s enough reading for me, it’s time to get Go-ing (not sorry). Basically, I’m going to follow along with the How I Start post and use that as a starting point.

I pretty much followed to post line-by-line, with the exception of how the API keys are handled. The thing is, I don’t want to check those into GitHub, but I also don’t want to have to remove the keys every time I make a commit. That sounds like the worst; and I’d probably forget to eventually. I don’t know what would be a good practice for this, so I’m going to put a pin it for now.

Okay, so at the end of How I Start, we have a little server that takes a city and gives us the temperature, and it queries multiple APIs concurrently, so that’s neat!

I know there are so many weather applications out there, but I think I’ll stick with it and see if I can give this one its own charms. Here are some things I’d like to add to this little project:

  • A front-end. I’m leaning towards a native Android application.
  • A third-party library for interacting with the weather provider. I’d rather not make my own at this point.
  • User authorization. I want this weather app to be a little more personal.
  • A database, for user info at least.
  • More data from the provider, not just the temperature (and not in Kelvin)

I’m looking forward to seeing what happens.