I
recently finished working a new piece of functionality on my job and it was a whole lot of
experience. Even though that's not the first significant feature that I produced and I do know what the process usually looks like, some of its
aspects caught me off-guard once again. It is wonderful how many surprises the
process of development bears for a developer and how these same surprises
continue to happen even after one passes through the process several times.
Of course
it all starts with enthusiasm. If you don't hate your job, new challenging
tasks always spur eagerness in you. Interestingly, the process of reading
through the feature specification and long lists of requirements usually even
makes it grow. The same is true about the attempts to lay out the general ideas
about the solution and outline each of its components. More broadly, any
planning and preparation activities increase willingness to get the problem
solved and even despite seeing numerous problems, we tend to maintain
motivation and good mood when getting ready for the actual work. Indeed, no
matter what, we plan for success and the more we plan the more real it feels
even when one sees that there are plenty of issues to overcome. One may even
interpret this observation as a bit of advice - whenever you feel overwhelmed
with problems and questions it may be a good idea to go and do a bit of
planning - even though it might feel like you have already laid out everything,
rethinking a particular piece of work might not only help understand it better,
but also encourage you to do it.
However,
once everything is planned and scheduled, one has to start development and
produce some, preferably working, code. While the process usually starts
smoothly, on some stage you smash into a seemingly impenetrable obstacle -
confusion. Speaking of me, when planning I tend to thoroughly analyze various
details of the future solution and study the existing bits of code, but I am
not required to produce anything working right away on this stage and can be
satisfied with a set of ideas and questions pinned down on a sheet of paper. On
the other side, when getting down to implementation one has to squeeze new code
into the mass of the application in such a manner that both old and new bits
work. The sources of confusion are plenty here: sometimes you will try to add a
new line of code in a method only to notice that you need to carry in 5 more
arguments for it, which would make the method much less comprehensible and
elegant (let alone the case when it is not elegant already). Or rather, you may
find yourself in a situation when you want to change a long run of code, but
feel that you miss some important ideas about it.
In my
case this confusion - or maybe we should call it frustration? - is usually
caused by a combination of two factors: the lack of understanding of the domain
and imperfections of the legacy code on top of which (or more likely, inside
which) I add new functionality. This doesn't mean that I start working on a
feature or project without any knowledge of the domain - there's just always
something that one doesn't understand and this is the norm. Similarly, the
people who wrote the code that I have to work with are usually smart
professionals, but their code is good for the task that they were solving - not
always for the problem that I am currently addressing. While one cannot escape
these difficulties, there is a way to tackle them - in the world of programming
this is done well by refactoring the existing program or component and
gradually injecting new pieces into it. While refactoring for its own sake
might well be considered a bad practice, refactoring as a way to understand the
code is a totally different story. Judging from my experience, there is hardly
any other way to comprehend a considerably large class or method. Additionally,
if you are changing the code anyway why shouldn't you make it more succinct and
elegant as well?
Now,
let's pretend I have paved my way around first obstacles and tackled the
difficulties - what next? First of all, there are first pieces of a reward
waiting for me. After I put some time into a feature, my head gradually wraps
around it and I start feeling that I am able to address all the problems in a
holistic and elegant manner and even make the existing solution a bit more
efficient. This confidence alone greatly helps to move forward. Bad news is
that these moments of high spirits usually alternate with periods when one
notices more and more unforeseen issues. It feels like the more problems you
solve, the more of them jump at you from nowhere. Even though good preliminary
analysis and planning are supposed to reduce the amount of surprises of this
flavor to minimum, they are never totally avoided. Sources might be different:
sometimes a customer visits you with a shiny new idea or a forgotten nuance, in
other cases you find out that a little change in one place impacts a distant
component in an unpleasant way, or maybe you notice that what seemed a
perfectly efficient and elegant redesign turns into an ugly muddle in light of
a tiny edge case that you missed. The general idea is that one should expect
the unexpected, because it always happens - usually in large amounts.
Fortunately,
at some stage the task that looked like a mess of deeply intertwined problems
becomes manageable and the carefully crafted solution takes the form of a solid
thing. You start to address newly found problems with great ease and with even
more impressing speed. You know the answers for most questions that one might
ask in relation to the feature and to its neighbors. Furthermore, you are able
to explain yourself and anyone willing to listen why the answers are those that
you give. This is the state of expertise - both in the problem and in the
solution (read implementation) - that is by itself a perfect reward for all
efforts, weekends spent at the office and even sleepless nights marked with
never ending search for a solution to some nasty problem. No matter whether the
feature is small or large, isolated or integrated with a dozen other modules,
one should feel proud when they reach this level of understanding and
familiarity with it.
When the
thing is almost done, however, new surprises come in. Like the final of any
Hollywood movie provides some clue to a sequel, any feature added to a software
product opens the door to dozens other enhancements, improvements and, well,
bugs. I thought that my inability to foresee all these consequences is caused
by the lack of experience, but it looks like even a group of experts can't
always predict which problems a portion of new functionality may bring to
existence. This basically means that there is no end to any particular feature
or component. More precisely, the development can only be finished when we
decide to finish it - you can't just do all of it. While this might feel
depressing, there is hardly anything bad about the fact that there is always
some work to be done. One should just remember this and be ready to postpone or
reject some of the new ideas when they block completion of the feature. This
will free you from the current burden and let you analyze all these new pieces
together in a calm and reasonable manner. What's more important however, is
that this way you will finally be able to mark the work item as resolved in the
issue tracker or move the sticker forward on your Agile board, face the sweet
feeling of achievement and have some celebration, because the thing is shipped!
While the
process of developing new functionality is often an interesting and challenging
activity, it might be difficult at times. You should just be ready to find
yourself confused, frustrated and overwhelmed. These bad moments are simply a
part of the process and their presence by no means suggests that something is
wrong with the feature being developed or with you, as the developer.
Eventually, these feelings will give place to satisfaction and pride with the
awesome component that you deliver and with the new level of expertise that you
reach through this undertaking.