a collection of lengthy notes on how I am usually coward to do what is wrong and how I am sometimes brave to do what is right. Bits of management and self management, .NET programming, Clojure parenthesis and lots of design mistakes are the things one will find here.

пятница, 24 октября 2014 г.

The last week I spent two or three hours
looking for the cause of a bug really close to the place where it was actually
located – but not close enough. From the exact moment when I opened the bug
description in Visual Studio everything pointed me in the right direction –
towards a couple lines in our code base, fixing which would have resolved the
issue. However, when reproducing it according to the steps outlined in
the issue tracker and exploring the related behavior of the system I have caught
a glimpse of something peculiar, that could have been the reason of my issue, and it made
me waste a lot of time on trying to fix the wrong problem.

A particularly important detail about this new problem that I discovered was that its incorrectness didn’t look like something trivial and minor. It
seemed to me that I was looking at a very severe bug spanning a number of components of our system. At some point, I
was almost sure that I have found a really big problem, much broader than what
the reporter could have thought. This feeling of stumbling upon something significant that might have far-fetching consequences quickly made me
forget my initial objective.

Moreover, I was excited in a very negative way
by the idea that I see something that other devs on the team have overlooked,
and the desire to show everyone how cool I am pushed me even further away from
what I should have been fixing. The fact that the newly found problem looked
much more complex than what followed from the original description also meant that it was more interesting. Hence, my
eagerness to fight it instead of taking a broader look and examining all the
aspects of the problematic process.

It took me a couple hours of digging and a relatively long break to persuade myself that I should try and go through all the steps that
cause data corruption and the related error. Initially, I have stopped my attempts to
find the exact source of the issue once I had spotted something strange and
unexpected. Should I just follow the description of the issue, carefully
crafted by the QA engineer, up to the point where the problem is clearly seen, I would have reached the root
of the problem much faster – maybe in a matter of minutes.

What happened instead is actually very familiar to me –
that’s not the first time I make this mistake. From time to time, when tracing
down a bug I face something strange-looking in the middle of the way and start exploring it. I do this despite being fully aware of the idea that any problem must be solved from where it manifests itself down to its
actual reason – without taking any shortcuts. I know that one should under no
circumstances skip any steps on this way, but I still do this occasionally and
it never brings me close to where I would be happy to find myself.

This exact problem is what the strategy of
moving slowly and in tiny steps aims to solve. For me the nature of the issue
began getting clearer once I pushed aside the keyboard and started writing – with
pen and paper. These tools make one work slower, they don’t allow to hack one’s
way through the code and skip crucial points. Moreover, they facilitate deeper
and calmer thinking, while rapidly stepping over the lines of code in a debugger or
executing numerous variations of an SQL query usually
descends one into a state where only wild guesses and ‘let-us-try-this’ hacks are
possible.

My takeaway is once again that one must not
rush to solve any problem that they happen to see – frequently what we initially perceive as incorrect behavior turns out to be desired in the end. Instead, one should work towards fixing what they aimed at first. In many cases problem solving works better if one maintains a queue of
the problems – not a stack. Fortunately, even though our minds seem to be using
a stack internally, we can always push extra problems out of it – to a bug-tracker
or to a good old sheet of paper – so that the original, the right problem can
be fully comprehended and solved, giving way to new glorious fixes.

пятница, 10 октября 2014 г.

During a recent discussion with my friends I
have faced an interesting contrast between what looked like the right thing to
do in a mobile application and what a more traditional UX common sense
suggests. While the way I thought the application should work seemed pretty reasonable
from the business point of view, my friends were reluctant to accept it. The
strength of their resistance to my approach descended me into doubtfulness and
made me search for flaws and the ways to align the app’s behavior to the
expectations of potential users without losing the emphasis on the business
process.

My task was very simple and can be described in
general terms without diving into details. The application deals with jobs,
which user is supposed to create. In addition to that, he needs to do some work
with the existing jobs – particularly assign workers to them. In terms of UI,
this boils down to several application pages, only two of which are of interest
now. The first one provides the inputs to set various attributes of a new job.
The second view comes with a list of jobs, which were just created but haven’t
been assigned a worker yet – user picks one there and selects workers for it.
Once this is done, the job leaves the list and moves further along the
pipeline. The problem sits right between these two pages: views on how the
transition between them should happen when user fills all the properties of a
new job and presses Create might differ a lot.

One approach, which you will find in many
widespread feed-based applications and which looks quite natural, suggests that
once the job is created it should appear on the top of the list and be the
first thing to draw user’s attention there. That happens, for example, when you post something to Twitter or
Instagram – when you tap Post in the corresponding
application, you are transferred back to the feed and see your new photo or
message added on top of it. This is the approach that my friends were
proposing. It actually has lots of benefits: user sees the item they have just
added and can not only check that everything is correct, but also take some action.
For example, right after publishing this entry I will want to look through it
to locate things like typos or extra blank lines between paragraphs, and it is
great that the blogging engine shows me the latest post first. However, for my
application it didn’t feel suitable.

What I have chosen to do instead was to keep
the list sorted by creation time in ascending order – the older the job the
higher it appears in the list. Moreover, the app doesn’t scroll the list down
to the newest item when the user adds it. For my friends this made an
impression that when the list is already long new jobs just vanish unnoticed
somewhere under the tower of older ones. While that certainly looks like that,
there are some reasons to lean towards this approach. In my opinion, these
fully justify the initial confusion that can arise from the fact that the feed
does not work the way Twitter does.

Firstly and most importantly, the application’s
purpose is to assist an employee in their interaction with a queue of customers
and the pool of workers. In such a situation, when service time is critical,
the older jobs are likely the hotter ones, meaning that if you have a job,
which lies unassigned for 30 minutes already, you definitely want to process it
before the one created a moment ago. Furthermore, since customers are served in
FIFO order, in a situation when the list of unassigned jobs is already long and
all workers are busy, arrival of a new customer should not interrupt the
ongoing process. Under these circumstances, the manager handling the queue –
our user – only has to put the new customer on the queue and forget about them.
It is not necessary and possibly even harmful to draw too much attention to
this new customer – instead of messing with a client, who has to wait for their
turn, we should first process the jobs, which entered the queue earlier. (Of
course, I don’t mean that the manager should literally forget about new
customers, but he must be focused on the ones who have already spent some time
in the queue.)

These considerations make me confident about
the second approach, which pays close attention to the process that the
application is supposed to help with – maybe in favor of complying with user’s
initial expectations. At the same time, the discussion that we had made me thoroughly consider the problem. The least important and most
obvious thought that I had in relation to it is that our views on how
something should work and look might be affected too much by the things, which
we interact with on the daily basis, despite the fact that the difference
between the two can be vast. Here I don’t mean that my friends are totally
addicted to Twitter. Instead, when they voiced their concerns over my design I
have found myself in doubt and seriously contemplating adoption of the more popular approach. It looks like we are too used to feeds of tweets,
photos, links and news growing from the ground up and sometimes oversee the fact that not everything should work this way.

More important takeaway is that doing the right
thing is not always the same as taking a popular and well-established approach
to UI. This flows naturally from the previous paragraph and merely suggests
that before jumping on the bandwagon of any time-honored and user-approved UX
pattern we must carefully study the goals of our products and how they can help
users achieve their own objectives. This means that behind any application there is a
process, which we try to enhance, improve and optimize and it is vital to take
every detail of it into account when designing the application.

Last but not least, what we face here is the
contradiction between user’s expectations and the goals of the software. When
facing something like this, we should not forget that keeping users
comfortable and amused is not the only purpose of a mobile (or any other)
application. It should be easy to work with a product and the latter must not
stay in the way of doing one’s job, but a business app occasionally has to make
the user uncomfortable and draw their attention to something that they might be
unhappy about. In the end, kittens, food and beautiful landscapes are for
Instagram, while business apps are all about doing business.

About

I work as a team-lead at Acumatica, the Cloud ERP. Besides, I hack code on my own for the sake of learning, fun and whatever else that programming can bring. To reflect on these activities and structure my thoughts and ideas better I also maintain a little blog.