суббота, 27 марта 2021 г.

Exploring a large pile of someone else's code

I am occasionally approached by students who are currently learning to program and are sometimes taken aback by assignments that look like "here is a mostly working app - go fix this and that to make it actually work". What they are looking for is some simple and reliable way to approach that huge pile of code that someone else has written and make sense of it, so that eventually it is possible to address the problems they are asked to fix.

Funny enough this not a student only problem - any working professional faces it whenever they join a new project that has already been running for some time without them. So for the sake of everyone who runs into this here are several things that I like to bear in mind whenever I run into a new code base.

1. Entry points

Any program (literally) has entry points - a limited number of code sections which connect the application to the external world. A CLI utility will normally have just one - there would be something akin to the main procedure that gets executed, whenever a user runs the utility. A web backend application will have a number of HTTP endpoints/routes which get fired whenever a corresponding request arrives (plus, again, the main function the performs the setup). A frontend application will expose a number of screens/pages available under particular routes. For example, in a React application with a router these would be some larger components mounted at particular routes. Or in the same React application you can treat the root component (who in many cases bears this proud an meaningless name App) as another such an entry point. All of these are the points in the code which get invoked by some external actions and start the journey of data and control flow through the code.

For any kind of a program you will be able to locate a number of such "entrances" and these serve as a good place to start exploration of the codebase due to a couple reasons. First, they are usually limited in quantity, which helps to concentrate. Second, and more important, when you start there, you have the benefit of understanding what happens to one side of the entry point - there is either a user or another system that performs some actions against the program being explored and thus 'calls' these entry points. This gives your exploration a better sense of direction - from an entry point you can only go deeper. Plus, it allows you to experiment - you can be that external thing - run the program a couple times or throw a couple requests at it and see how it behaves.

2. Database / persistent storage

Many applications (here I can't use that nice term "all") utilize some kind of storage - maybe they save some stuff to files or manipulate records in a database. In any case, these may aide your exploration efforts. Here you get a chance to understand what kind of data the program manipulates, how it choses to represent and store it. You may also experiment: throw a request at a web app and see how it affects its database.

The goal here is to grasp the program's data model and see how it is utilized - that illuminates a lot about the program itself. You would want to see which classes represent which kinds of data here or which functions create or read which records, and who calls them. Manipulating data is what most of the code is about, so understanding what data is at hand inevitably helps understanding the code.

3. Find yourself a simple challenge

When it comes to action, find yourself a very simple task that actually involves changing some code and do it. Maybe the original set of problems that you came here to solve includes something simple. If it doesn't - just invent it. When you're dealing with a frontend app such simple task can be tweaking the order of controls or changing the colors of some UI elements. If you work with an HTTP backend, try to add an optional filter to a GET request handler or to prevent updates for records based on any kind of criteria, which you can control.

The common place here is to keep this first task trivial - without even the goal of doing something meaningful. That's a good idea because at this stage you're still focused on getting a feeling of the code, learning to navigate it and validating that your changes actually have some effect. Once you're done with that you'll have some stable grounds under your feet: the code will feel more familiar, you'll develop some understanding of what's available to you and feel more confident about solving more complicated issues.

4. Breadth, then depth

Here is another thing that I keep returning to again and again. When facing something large you'd normally want to study what is it on higher level first, without going into details. If we speak of the entry points, identify all of them before trying to make sense of the implementation details of any particular one. When you're exploring the data model list all the tables / collections and how they are related to each other before studying in depth what and how each of them stores.

This is useful because having a broad understanding of what the whole thing deals with will help to have better ideas about the implementation details when you dive into them - having some context is always valuable. On top of that, many bits of code will work with several higher level concepts at once, so it's useful to have a rough understanding of what these are in the first place. If you get and overview of the landscape first, exploring the details will feel more like connecting the dots, rather than just wandering in the dark - don't get yourself lost too quickly.

5. Use tests

If you're lucky enough, the project that you're coming to will have some tests, which would serve as a superweapon to study it. Tests encode developer's assumptions about the code, so just reading them carefully may shed light on a lot of things. Moreover, you can change them and see what happens. And if that's not enough, you can actually play with the code itself trying to break specific things - tests will show you whether your assumptions about what breaks what are correct.

If there are no tests your position is weaker, but there is still a wat to go - try rolling up a couple unit tests for some bits of logic on your own. It turns out, testing someone else's code is the second best way to understand it, so don't ignore that. Just don't take that too far - your goal here is not to ensure 100% test coverage, but rather to make a couple assumptions about the code that you're studying and proof them right.

6. Refactor

I said testing is the second best way to make sense of unfamiliar bits of code. The best one is refactoring. In practical terms that means taking that part of code that you're interested in - a function or a class - and trying to rework it in any way that you find plausible with the main goal of making every step of it clearer to you. Don't get me wrong here - I am far from stating that it is easy to make code better when you barely understand what's going on there. The point is to try to rewrite something and thus understand it better and then just discard all of your changes. If you already have tests to support you, the effect will be tremendous - essentially you will reimplement the sections of code, which you intended to understand, and it is quite hard (although possible) to do that without developing a degree of understanding on the way. (If you don't have tests, you know what to do first).

7. Write it down

The task of fixing a couple bugs or implementing a feature in an unfamiliar repository is akin to the quest of entering a labyrinth in hope to find a couple gems in there, when you know what the gems should look like but have zero idea about the place itself. If the maze is fancy enough, finding all the gems will involve a lot of going back and forth and getting lost sometimes. To make it easier make yourself a map while you're traveling. Write down what you're after, fix your assumptions, chart the course, pin down whichever discoveries you make on your way, note what doesn't work and why.

This may sound like a lot of extra work and a major distraction, but it is not as time consuming as it sounds, while the benefits are grand. One reason, why you want to do that is it helps to get back on track when you feel lost of trying several things that don't work. Another is that taking time to make notes will help you avoid the rush of just trying to hack a couple things together. When you're familiar with the codebase doing things quickly can be fine - your deep understanding helps you make the right decisions about what to do where fast. However, while you're only making yourself comfortable with the program a more thoughtful, slow but steady approach will be more apt and will also equip you with deeper knowledge for whatever comes next.

8. Be brave and humble

Above all, don't be afraid to start and start small. Don't take a big challenge at once - break it down into smaller, easier to approach problems and handle them one by one. As long as you are taking steps, you will eventually arrive at some place. And if you take small and carefully planned steps, you will get there sooner and will see that it's the right place.

четверг, 1 октября 2020 г.

Three Starters

During the last weeks among other things I've been repeatedly facing each of the following three completely unrelated tasks:

  • Work with an HTTP API either to test it or to run a series of files/data-based queries, for example, to upload some data to a new service or to check how a service responds to particular kind of HTTP load,
  • Configure basic HTTP endpoints monitoring with alerts sent to a messenger,
  • Create a simple NextJS website.
I expect to run into each of these tasks again more than once, so I assembled three starter repositories, which I can simply clone and reconfigure according to the needs of the next projects. All three are available on github - feel free to use in your own endeavours.

Clojure HTTP Playground

Use REPL to run any kinds of http requests, utlizing full power and interactivity of Clojure to process the data being sent and received.



Prometheus Blackbox Probing Starter

Set up basic available/unavailable monitoring with Telegram alerts for HTTP(S) endpoints


NextJS Website Starter

Bootstrap a simple website/landing, starting with basic styling, some degree of responsiveness, a couple reusable components and (hopefully) easily reconfigurable color theme.


среда, 12 августа 2020 г.

Image magic

I've been facing the task of manipulating images for web apps and websites from time to time - like cropping, scaling and reducing file size. While some of these tasks can be done with a handy GUI tool like Photoshop (you have to pay for it), Photopea (a very powerful web-based photoshop-like editor that works with a multitude of formats including .psd) or Paint.net, sometimes a shell-based tool will do so much better. 

There is a tool like that and it's called Imagemagick

The thing let's you manipulate various raster images in different ways. I would most often use it for resizing and compressing images in batches and sometimes for cropping (here a visual tool may be better, but really depends on the scenario). 

For my own and other's reference, here are some of my usecases. Of course, there is an extensive documentation on the tool's website. 

(Since I'm on windows, I use image magick in Powershell to process many files at once).


Crop

Crop all files in the current directory and save them with a .crop suffix. This one reduces the size of the images to 1080x1732 cutting off 62px on the top (android screenshot).

Get-ChildItem -File | Foreach {convert $_.fullname -crop 1080x1732+0+62 $_.fullname.replace(".png",".crop.png")}


Scale

Scale all files in a directory down to 50% their dimensions (preserves aspect ratio):

Get-ChildItem -File | % {convert -resize 50% $_.fullname $_.fullname}

Compress


Just one file, saving a copy:

convert -strip -interlace Plane -quality 85% .\banner_1.jpg .\banner_1.comp.jpg

All files in the current directory, replacing the originals:

Get-ChildItem -File | % {convert -strip -interlace Plane -quality 85% $_.fullname $_.fullname}

A lot of other usecases - do explore them!

пятница, 7 августа 2020 г.

How to handle a programming problem


A couple students whom I mentor through a software development course recently asked me for a generic advice on a way to approach a relatively large software development - something that would help them know where and how to start producing a solution. The question definitely provoked several pretty deep discussions. Since I do expect other students to seek advice of a similar kind I decided to devote a bit more time to the framing my advice.

While contemplating and discussing the topic I came up with a number of points that depict the approach that I use to build software. Sometimes I would follow this process to the point, in other cases I just adhere to the general line of thinking that it suggests - it definitely depends on the kind and size of a particular project. Thus, even though I present the approach as a sequence of steps, it is most reasonable to treat it as a description of a way of thinking about a programming problem.

Note that it so happened that I faced the question soon after going back to the Code Complete book to check a couple chapters. Moreover, I was reading How to Solve It by George Polya roughly at the same time. Because both of these have a lot to do with the topic at hand, the post definitely builds on the ideas found there. I absolutely recommend both of these books in case you didn't give these a try yet.

So, you find yourself with the task of producing a piece of software that would solve a particular issue. What should you do?
  1. First and foremost, state your problem in writing - what are you trying to solve?
  2. What requirements should the solution satisfy? Jot every one of these down as well.
  3. Imagine the final solution, state in writing what the thing that you are about to build will look like. Focus on the general shape of the final result here. See how it will solve the problem and meet the requirements.
  4. Think over the data model. Decide what kinds of data you will be handling, how to structure it better, where it comes from and where it should go. Imagine how the information is split into tables and collections, spot the relations between them. Consider which bits you need to store and how. Do this even if you don't have any kind of database - maybe building only a frontend application - data is something that you work with in any software and it definitely plays a great role in shaping the solution. Write all of this down.
  5. Decompose your future system or program based on what you have understood so far - think over how you can split the problem and the solution into pieces. Depending on the scale of the task you may be thinking on the level of services, modules or classes and functions here. The larger the problem - the larger should be the size of units considered on this design stage.
  6. In this process follow the breadth-first approach - e.g. don't go into designing functions before you produce an overview on the level of modules. List the large-scale units first, state their purpose clearly and only once this is done permit yourself to descend to the next level of detail. Notice when your start jumping between different levels of design - like thinking of modules, then functions, then modules again. If this happens stop and pull yourself back to the highest level that still needs clarifying.
  7. Don't overdesign and keep moving. Most of the technical design will happen while you're coding. Your key goal at the moment is to draw yourself a clear image of the whole solution, its components and relations that govern them and to see how you will meet every bit of requirements. Design can consume infinite time, so don't let yourself get lost in it - details will come.
  8. After facing your components think over your past experience - each component poses a smaller problem to solve and many of these smaller problems you may have solved in the past. If so, check which bits of previous projects you can use now - this may mean anything from pulling in a dozen existing files to just reviewing how you approached a particular issue a couple months ago.
  9. Throughout all these stages use pencil, draw figures, sketch stuff, write things down - it helps you think. Once you have started producing a diagram, your mind will follow. Draw how the system or its particular component is decomposed, outline relations between the pieces, sketch the data flow, chart user actions sequence.
  10. Devise a plan. Decide in which order you will build your components. Write that down (in any form or medium) - that will help you see and maintain progress, especially with longer projects
  11. Pick the first component on the list. Jot down the steps to build it. Think how to test it, list the functions to implement, decide on the order, add checkboxes. If you don't know how to pick the starting point, pick any single one of them. At this stage it’s most important just to start the job, so start anywhere. Even if you choose a wrong initial task, you will soon be able to see and correct that.
  12. Go and start writing the code. The first lines may go hard, but with all the preparatory work you should be able to break through them and the rest will follow easily.
  13. Don't try to write perfect code from scratch - start dirty. Starting is a challenge by itself, so simplify the task and relax the requirements. It is much easier to produce a dirty solution and clean it once you see it working. Just don't forget to always clean the mess.
  14. Write tests as you go to stay confident in the state of your code. Confidence does matter a lot here and the lack of it may slow you down significantly.
  15. Iterate. Pick small tasks, complete them, polish the solution, celebrate, step back to take a look at your design and plan, repeat.
  16. When you face challenges and are not sure where to go from there, take a pencil and think. State the problem that you're trying to solve, write out the required characteristics of the solution, draw, see it and then implement it.
  17. Yes, look for what others have to say about your problem - stackoverflow, github and google are your friends. Don’t just grab any code that you find on the web though - take time to understand what it does, why it works and what kind of new issues it may throw at you.
  18. When all else fails, go away for some time - take a walk, wash the dishes, smoke a pipe, use your hammock time. Let your brain wander away. Most times you will come back with new ideas. In the worst case you will get some rest and have more energy to continue attacking the problem.
And finally, if there are no more tasks to do, everything is polished and you feel happy about the result, celebrate the success, reward yourself, think over the lessons to learn from this project and go look for the next issue to solve. If you can program, there is an infinite number of problems waiting for you!

понедельник, 8 июля 2019 г.

Takeaways from the Preparing Slides Course

About a week ago I finished going through the Presentation Skills: Designing Presentation Slides course on Coursera. It proved to be a rather helpful guide for someone fully depraved of the ability to assemble anything that looks good in PowerPoint. If you belong to this kind like I did, I fully recommend the course - that's a moderate investment that offers quick returns. Below are some of the key lessons that I learnt from the course:

  1. While working on slides I must ensure three things:
    • Focus – I should draw the attention of my audience to the most important idea on the slide,
    • Contrast – the slide should communicate what is most important and what is the detail of secondary importance,
    • Unity – the slide should focus on one thing or idea; I should search for things that can be removed.
  2. Slides should be functional, look professionally and entertain when possible. Order matters.
  3. There’s no such thing as “too much text” – rather “too much text out of context”. In other words, if the text is important it can be properly arranged and styled in such a way that the slide will be readable – the problem is usually how we present the text.
  4. Allowed level of complexity (e.g. of a chart on a slide) depends strongly on the readiness of the audience to perceive it. The size of the audience is a good proxy for that readiness: the larger the audience the less ready it is to try to understand complex stuff.
  5. Less decoration is good. Adding decoration doesn’t make the slide look good – introducing structure does that. Overall, I should try to remove as much decoration as I can – in particular in tables.
  6. You can achieve a lot in terms of readability by means of good structure and typography.
  7. Outside of the branding-related decoration/slide template I may use a maximum of two colors.
  8. One of which is the color of the main text – black, dark gray or dark blue.
  9. I may use another color for a couple crucial words or, better, icons and focal points like that
  10. Max 2-3 words should be bold.
  11. Bold means more important, italics means less important. Sounds controversial, but visually looks reasonable: bold stands out from the slide, while italics sort of leans to the background.
  12. Font size should be used to introduce structure, which should communicate importance.
  13. Photos should be large and few, icons – small and numerous.
  14. Bullet lists can be arranged horizontally and they look better and more readable this way – because it allows to introduce clearer structure and contrast.
  15. There are the Align and Distribute tools in PowerPoint – save a lot of time arranging stuff on the slide when building structure.
  16. Plus a dozen interesting and practical details about typography, colors and visuals on the slides.


воскресенье, 7 апреля 2019 г.

Failure Checklist

Just about a year ago - early 2018 - I decided that I am ready to quit the job and build a business of my own in the wild. I won't go through the details of how I came to that and what happenned next - the important part is that after 8 months I have found myself running out of cash and not knowing what I can do except to look for a new employer.

By the end of 2018 I have successfully landed a job - a great one, by the way. So now I am safe and already had some time to contemplate my attempts at business. Here are the key conclusions that I made from the analysis of what I did and how that led me to the failure:

1. If you go into business, you absolutely have to design a sales proposition that would clearly show your potential customers what you are offering, how much it costs and exactly how much they would benefit from it. In other words, you have to present your customers a cost-benefit analysis of your offering. Once you have it, advertise it a lot and do be ready to pay for the ads.

2. Be sure to prepare a financial model of every business project that you are trying to build. If the model shows adequate income, don't abandon it even if you see only modest earnings per unit - you just have to scale it properly.

3. Your business model doesn't have to be cool or show few competitors, but it absolutely must allow for reasonable net income in the target market. Other things do not matter much.

4. You have to be ready to overcome difficulties, do something when it's not clear what to do and ask other people for help at solving the problems of your business. The only allowed reasons to abandon a business are poor cash flow or the act of discovering why your model can't generate proper income. No other difficulties can be a valid reason to quit trying.

5. You have to go and sell your product in each and every possible way - including those, which are least comfortable (or even painful) for you. You must not stop trying to sell until you understand why your attempts fail and why you can't fix that for an acceptable price.

6. Your work must be focused on closing the key needs or problems of your customers in the first place - not on something that you find important or cool. Whatever you add to your product or service must be helping you sell it. Of course, you have to start with identifying what are these things crucial to your existing and future customers.

7. It is important to extrapolate your positive experience and translate every successful deal into a clear offer that would be interesting for a wider market. Once you figure out how to adapt what you have done for one client to the needs of many others, go and sell it to them.

8. Focus on just one or two (absolute maximum!) projects at a time. Don't dive into any new shiny projects until you finish the current one. Remember, there is one good reason to abandon a project: either it fails to generate adequate net income or you absolutely can't find a way to live to the moment when it would finally start bringing that income.

These thoughts look obvious, but when it came to the actual work I managed to violate each and every one of them. I learned the lesson the hard way, but the next time I venture into something new, this will be a good checklist to validate what I am doing on a daily basis. If, on the other side, you are just about to start a business of your own, this may help you avoid the mistakes that I made.

суббота, 30 марта 2019 г.

The Moneyball Takeaways

I recently watched the Moneyball movie - a biopic after Billy Beane, the manager of the Oakland Athletics baseball team. It’s hard to imagine anything less relevant to me than baseball, but the movie is in large not about the game itself, but rather about how it’s managed and changed, so it did hit the right strings. 

The plot revolves around a baseball team manager trying to change the rules and build a team that would win under severe budget constraints - totally about management and, particularly, change management. Below are the key thoughts that got running through my head by the time the end titles made it to the screen.

  1. If you gonna change the rules, there would be people who will oppose you. No exceptions. 
  2. If you gonna change all the rules, almost everyone will oppose.
  3. There still will be people who support you - keep them, teach them, trust them and respect them.
  4. Building a winning team is not about picking the top players - it’s rather about picking the right ones, who cover the needs of the team.
  5. The needs of the team is what it has to do to win - preferably, expressed in figures. Nothing else matters.
  6. Winning is all about performance, performance is all about measurement - neither is about whom you like and whom you don’t.
  7. While building a team you will certainly have to hire people, but likewise you will have to fire someone.
  8. By the time the game begins the manager’s job is done - they can only watch how it develops and make a note of any required adjustments.
  9. The fact that you succeed at changing the world doesn’t mean that you win. 



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

Use Trello as the good old day planner


In the old days of my first attempts to plan my work ahead instead of simply following the stream of life I used a paper-based personal day planner - a thing that everyone had at some point. It is a great tool that has almost everything that one needs to plan their days. But it's also another large and heavy thing, which you have to carry with you. Also, because it's pen and paper it becomes a mess for example when you have to adjust your plan because something went wrong, and it is limited in space. Thus, with time I switched to Trello as my organizer and followed the Getting Things Done methodology in it. It works great, but I always missed the ability to plan the following day accurately and to follow that plan closely, which I could do with the paper thing. Recently I discovered a way to fix that and it boosted my productivity tremendously.

My Trello board for daily activities is constituted of several lists, such as Incoming, Wait, Office - Do and Wilderness - Do. The latter two are action lists - they consist of the things that I am going to do at the office and elsewhere. During the day I go through the cards in these two lists, do them one by one, and archive each one when it's done.

When I first switched to this approach I lacked the ability to plan the next day - action lists could include lots of cards that would span several days and it didn't work well for planning. Sometimes I would make a kind of plan on a piece of paper, but in most cases I simply didn't do it. This made me miss the paper organizer. This problemm however, is easy to fix without leaving the comfort of Trello.

At first I simply added a card called "Day boundary" with a black label to my two action lists. I don't use black label for anything else so it is easy to spot this card among others. The meaning of it is simple: whatever is above it should be done today; what goes below will be done on any other day. This trick helped a lot: I could plan my day now. Whenever something changed I could easily adjust plans by moving things that do not fit the day anymore under that "Day boundary". The approach however was not perfect. Too frequently at the end of the day I would see a lot of cards above the black one, indicating that I failed to do all that I planned. While this can happen, seeing this every other day means I wasn't doing good job at planning.

I felt the longing for the paper organizer again. What I missed about it was the ability to see that between 13:00 and 14:00 I should be occuppied with one thing and also that if I don't finish it on time the things planned for later hours will drift by that much. This makes me more disciplined. Also, when laying out a plan in a paper organizer you have to fit its points into hour lines, which means you assess how long each one will take and whether they fit the day. In Trello I only had a list of things that I was going to complete over a very long period - one day - and it was very easy to make mistakes about how much I can put in.

So I made the next step and just added several more black cards to the action lists and labeled them with time: 9:00, 12:00, 15:00, 18:00, 21:00. It was enough to transform my Trello into as good an organizer as the paper planner. Now, every evening I fill the gaps between these black cards with action cards. Whatever falls between the 12:00 card and the 15:00 card is planned to be completed during that exact period of time. It also made my planning more realistic - I have to assess whether particular cards fit into a shorter period of 3 hours or not. To make that easier I made a custom of writing the amount of time allocated for every activity on its card (you can see the numbers in parenthesis).



During the day I still archive the action cards once I finish working on them. With the new organization this means that I can easily see how much I lag behind or how far I am ahead of plan. If it's 16:00 and I still have any non-black cards above the 15:00 one, then something went wrong. If all cards are below and there aren't too many of them between 15:00 and 18:00, I am likely good. It's 17:00 now, so you can see that I am falling behind a bit, but not too much. With these recent changes I returned to the state when what I planned for a day is actually done on that day. I may fail a little here or there, but generally it works well.

It doesn't matter much which tool you use to organize yourself as long as it makes you feel comfortable and allows to make a plan and see clearly how it is going while you're working through it. Trello's flexibility lets you achieve that easily and in a very visual form, so if you're not using anything specific right now it may be a good way to go.

If you have a different approach to preparing a plan for a day and working with it, please share it here! Maybe something about it makes you feel sick? If so, leave a comment and who knows - maybe we can find a solution together.

понедельник, 12 июня 2017 г.

The Simplest Way to Mess Up om/build

I played with ClojureScript Om recently and, while working on a stupidly simple task, stumbled into a strange problem when my components losed state and got re-rendered whenver a user attempted any interactions that caused the underlying data to change.

I had a component that was bound to a path in app state holding a vector of maps. It consisted of several identical components, whose purpose was to edit values in these maps. Each of these editors updated the corresponding value during the onChange event - whenever a user would edit the text in them. An important detail is also that these editors had state - they could either be in "view" mode (rendered as <span>) or in the "edit" mode (rendered as <input>). The thing transitions to the "edit" mode when it is clicked and jumps back after user hits Enter in the input or moves focus somewhere else. It all worked pretty fine until I actually started editing stuff - whenever I pressed a key all the components would get re-rendered and, more importantly, lose the editing state.

I attempted some debugging and code tweaking, but nothing helped or even shed the light on what was going on - I saw that the controls were re-rendering, saw that their state was lost immediately after edits and later even noticed that they are being mounted as new ones after edits. This later observation explained the problem with lost state, but didn't give me much clue onto why that was happenning. However the thing got clear after I read the documentation for om's build and build-all functions a couple times:

build
(defn build
  ([f x] ...)
  ([f x m] ...))
Constructs an Om component. f must be a function that returns an instance of om.core/IRender or om.core/IRenderState. f must take two arguments - a value and the backing Om component usually referred to as the owner. f can take a third argument if :opts is specified in m. The component is identified by the function f. Changing f to a different function will construct a new component, while changing the return value will not change component. x can be any value. m is an optional map of options.

At some point I noticed my dumb mistake - I was calling build-all like this:
(defn component [data owner]
   (reify
     om/IRender
     (render [_]
       (html
        [:div.container
         (om/build-all (fn [data owner opts]
                        (if some-condition
                          (edit-component1 data owner opts)
                          (edit-component2 data owner opts)))
                       (:attributes data)
                       {:key :attribute-id
                        :opts {}})]))))

Which means that on each render of the parent component I would pass a new function to build-all. Because components "are identified by their functions", that meant that on every change of the underlying state the parent component will start re-rendering the child ones, see a new function created by the (fn []) form and believe that it is rendering new components. Thus it won't even want to connect the old state to them and they will be rendered in the default "view" state.

Simply changing my code to the following dirty thing immediately resolved the issue:
(defn edit-component [data owner opts]
 (if some-condition
   (edit-component1 data owner opts)
   (edit-component2 data owner opts)))

(defn component [data owner]
   (reify
     om/IRender
     (render [_]
       (html
        [:div.container
         (om/build-all edit-component
                       (:attributes data)
                       {:key :attribute-id
                        :opts {}})]))))

The conclusion is simple: never ever pass to build or build-all a function that you create in the render method of the parent component or in any other bit of code that is called multiple times over the lifetime of your components. If you do this you will get new components built everytime and thus lose whatever information you associate with them (plus some time for their creation). I hope that you never commit this mistake, because that's one of the dumb things that require time to spot, but if you are unfortunate to run into it, this note may help.

понедельник, 29 мая 2017 г.

(= (+ clojure emacs) :happiness)

I started programming in Clojure quite long ago and despite all the great advice spread through the Internet kept using Sublime Text editor for it (it's an awesome thing, anyway). However some months ago I stumbled upon Emacs - maybe after talking to some Haskell-ists. Yes, it felt totally unfamiliar and awkward and I had to spend minutes trying to accomplish the simplest things that took me an instant to do in other editors. Still, I can't explain why, it felt quite likeable and more suitable for doing Clojure. The funny part though is that I'm only starting to learn the full power of Emacs as a Clojure programming environment. Literally, it took me almost half a year to get accustomed with the editor and its addons - mostly Cider - to understand how much one can do there.

Even though there are guides on the web explaining what a Clojurist can do in Emacs (for example here and here), I feel the need to list the basic tricks that I have learnt here. For some it may soften the learning curve, others will possibly provide some greate advice to me. And it will certainly help me if I somehow got struck by amnesia in these dangerous times.

First things first. Once I run Emacs to do some Clojure or ClojureScript I make sure to press C-c M-j or C-c M-J (for cljs) to launch a REPL and have it ready. Most of the cider's awesome stuff won't work without that, but it is also simply stupid to do Clojure without having a hot REPL nearby.

At first I used to copy and paste lines from code buffers to REPL and run them there, when I wanted to check whether something would work. Quite recently I discovered that this is stupid as well. One can simply place a cursor at the end of an expression and type C-c C-e - cider will evaluate the expression and show the result right next to it!

I had some problems with that though, because once I wanted to copy the result of that expression elsewhere and couldn't figure out a way to do that. Fortunately, one can get pretty close: C-c C-p will also evaluate the last expression, but the pretty-printed result will appear in a special buffer. Afterwards you can go to that buffer, skim through it and copy the required bits.

The last time I used that trick my goal was to select some values from the database (yes, with Clojure, because with Emacs it's closer that any other gateway to the DB) and use them as parameters to test my web-service. I made calls to that service through a plugin for Google Chrome (yes, not familiar with curl), but I should definitely change that to running requests right from Emacs itself - that should be pretty easy. Frankly speaking, I don't know any other development environment that allows to make a couple calls and check whether a webservice that you're hacking together yields the expected results without even leaving the window (correction: buffer) in which you write the service's code.

The last big thing on my list are tests. I used to run tests through the terminal, like lein test. Yes, that means spinning up a JVM, which is 15+ seconds at best. Try to imagine my feelings when I first discovered that I can run all tests in a namespace simply by pressing C-c C-t C-n, while there. Even better, I can run the tests that I have for one of my modules (i.e. namespaces) without leaving the buffer of that namespace - with those same keys. This one, however, requires that the namespace with tests is called <the thing that you're testing>-test - it took me some time to learn and get accustomed to, but that's not a big deal. Also, while the cursor is on a particular test case I can run it with C-c C-t C-t. Then change it and run again in an instant. As a C# programmer I love Visual Studio, but unit tests experience there is by no means close to what you see in Emacs with Cider.

Sometimes I would also type C-c C-x just to see that my code still compiles - that's cider refresh, which reloads everything.

And one more thing, that makes cider-ed Emacs a true development environment is the M-. hotkey, that navigates you to the definition of whatever you're looking at. It does have glitches from time to time, but it's there.

There's a ton of other greatness in Cider, I'm sure. Many bits are easy to find and learn through the hotkeys reference C-h C-m - I simply didn't internalize most of it yet. For example, there are keys and commands for macro expansion and multiple other things. Still, even with the few tricks that I mentioned above I get programming experience that simply seems out of reach for the other languages and environments that I worked with. If you do Clojure and your environment of choice doesn't give you the same capabilities, you should definitely check out Emacs!

вторник, 11 апреля 2017 г.

Takeaways: Ideal Executive by Ichak Kalderon Adizes

This entry also appears in my other blog.

I have already recommended the Management and Mismanagement Styles book by Ichak Kalderon Adizes earlier and now there is another title by Adizes that should draw your attention The book is called The Ideal Executive. Why you cannot be one and to do about it, which actually precedes the Management Styles. The two share some portion of content, but focus on slightly different aspects of management and are both definitely worth reading. To get you the idea and make myself a short summary I will list the key things, which I noted in the Ideal Executive.

First of all, both books use the same framework to reason about managers and their work - PAEI. The acronym stands for four distinct functions that a manager should perform: Production, Administration, Entrepreneurship and Integration. They are explained in great detail in the books, but the key idea about these is that all four are crucial to proper management. At the same time because they sometimes come in conflict with each other, no single person can execute all of them alone, which is why there is no such thing as an ideal executive. The only reasonable way to address this issue is to assemble a team of managers, each of whom masters in some of these functions, and let it drive the organization forward. The books focus on this idea and revolve around its various implications.

Adizes goes deeply into analyzing various aspects of the management job and of the idea of a management team, mapping them to the PAEI framework. I will just list various disconnected bits that attracted my attention in the book:

• The solution to the "no ideal manager problem" is a management mix of several people with different approaches: P will focus on what we have and how to get the best out of it, E will introduce desires and drive progress, A will make sure that everyone is doing what they should, I will connect and encourage everyone;
• Even though current objectives of the members may differ significantly, the team must have common long-term interests. Management means not only making decisions, but also implementing them. The latter doesn't happen if long term interests of the team-members are in conflict;
• Four factors that enable trust and respect in an organization are: people, process that includes communication, structure that allows people to match their interests to interests of the entire organization and ensures that reward meets responsibility, common vision and values ensured by leaders
• Structure must reasonably define the responsibilities, the extent of freedom for decision making and rewards allocation for P, A, E, I styles, because in each case these things should be different;
• Managers of different styles need different approaches because to large extent they speak different languages. Even "yes" and "no" may mean different things to them;
• When arriving into high-P's office don't start explanation from the early days of humanity - start at the end and with the conclusions, then move to additional info. High-P's hate extra details - they want to get things done as quickly as possible;
• When you are about to introduce your cool new idea to a high-E make an obvious mistake right in the beginning of your explanation of the problem - fixing it would allow high-E to feel his contribution to the solution. Otherwise he may get unhappy about you making a decision without his input;
• Conflict is an important part of the work and management process. It should not be avoided, but should be kept constructive through proper management;
• When discussing a decision and there is no consensus break all the apparent issues into three categories: questions, doubts and objections. Collaborate to answer questions first, then label doubts as questions and objections as doubts, answer the new questions. On the last stage you will hopefully have only the questions that were initially considered objections and will likely be able to resolve them as well. This looks like a psychological trick making people in the room focus on collaboration and making an idea workable instead of opposing it;
• Leader is a person who does Integration and one other function excellently and is at least good with the other too;
• Leader is like a thumb - its presence unites other fingers into a functional hand;
• Good leader acts as a servant, who creates the circumstances in which others can shine;
• Good leader can be distinguished by the scars on his tongue, because he keeps biting it to keep quiet when there is too much temptation to engage into a loud debate;
• Best managers keep calm when a conflict rises. The hotter the conflict, the calmer the manager;
• A manager must be able to hire, use, develop and reward people who don't look like him;
• Create circumstances in which conflict serves as an education tool and stays constructive;
• Organization is what it does for others. Answering the following questions helps understand it better and formulate its goals and values:
○ Who are the customers and what do they want?
○ Which of their needs do we address?
○ Which of their needs we don't address?
○ What are our abilities - what we can do?
• The goals and values should be periodically reviewed - otherwise you will get stuck in a set of irrelevant rules, which will prevent growth of the company;
• Currently management schools teach correct answers instead of teaching how to ask the right questions;

The book is a pleasure to read, and at the same time it provides a lot of advice in regards to management. This advice comes in a solid yet simple framework that helps reason about what one should be doing at his or her job and how it is different from what he or she is actually doing. The nice thing is that both the advice and the framework are very practical - learning these helped me notice many new things about the behavior of my colleagues and see some underdeveloped areas in my our activities, thus growing one step closer to the non-existent ideal manager.

понедельник, 13 марта 2017 г.

What I Expect from a Developer’s Resumé

This post also appears in my blog on Medium.

On a recent local programmers meetup we discussed the topic of writing a developer's CV in such a way that it allows one to get to an interview past the initial screening. As this is closely related to my posts on interviewing developers, I will cover what we discussed and what are the things, which when seen in a programmer's resume make the team-lead in me eager to meet its owner in person.

For all technical positions the first thing that both the recruiter and the team lead will search in a CV is work experience with relevant technologies and tools. This is the easiest one, because if you have it you just need to make it stand out. To do so make sure that you resume has the keywords that describe the technologies that you would like to work with. While people are quite different from Google search engine, when I look for a new hire I inevitably have to scan dozens of CVs and the easier it is for me to spot the names of the technologies that I need, the higher the chance that I will pay attention to the candidate. Trivial, right? Just remember that you have to be honest about what you have experience with and what you don't - if you're caught lying about these things, you will likely be wiped out from the list of candidates at the same instant.

On the other side, a resume consisting solely of keywords will be even less successful than a resume with no single one. That's because merely "knowing" all the buzzwords doesn't make you a professional, while having lots of achievements in the field of software development does. Here make sure that every job or internship mentioned in the CV lists every one of your accomplishments on that position - ideally, focus on what you have done instead of what you have been doing. Moreover, don't stop on the jobs - remember all the pet projects that you had done alone or with your friends, remember every conference that you talked at and the articles that you have written - all of these underline the experience that you reported and show that you're a person of achievement.

Such activities as pet projects and extra education - an open-source library that you helped to develop or a course that you have taken online - also show that you are willing and capable of learning new skills and technologies. That's especially good if these go beyond your main programming language or framework of choice, because breadth of experience demonstrates your ability to adapt to changing circumstances and employ different mind-models and approaches. Mentioning such activities in a resume also draws a potential employers' attention to one more thing - your fascination with the profession and desire to work and learn beyond your day job, which by itself puts you in front of the crowd.

Another important note is that all of us look for reliable employees, which in particular means that we want them to stay with us as long as possible. Planting a developer into the team and bringing him or her up to speed may take an awful lot of time, so when the process starts I want to be as confident about the result as possible. Essentially this means that a CV consisting of a long list of short jobs - e.g. those under 18 months each - will at least get me concerned. That's not something that you can change about your resume right now, but the thing is certainly worth remembering when you think over your next career move. I don't mean that you should stick to one job for decades, but after you're sort of settled with your career people may expect that you don't change employers too often.

Finally, the resume must allow you to express yourself in a clear and comprehensible manner. In particular this means that you should adhere to the generally adopted standards, such as listing your jobs from the most to the least recent one, displaying a photo of yours and so on. However, there is more to this, because to show that you're a person worth speaking to you must be polite and caring. In written communication that means that you don't brag too much, your language is good, its style is appropriate and there aren't many typos. You will also want to save your interviewers the time needed to find you at Facebook, Twitter, GitHub and elsewhere, showing that you have things to share and don't put crazy stuff up for public display.

It's that simple in regards to the contents of a resume, but I also have a couple suggestions in regards to the process of producing it. First of all, be sure to use external help when preparing the resume. Simply ask a friend, a teacher or even me to review the resume - an extra pair of eyes will spot mistakes and unclear sentences, which will help you look better. Some people prefer to ask a professional to prepare a CV for them. Here I can't advice much as I never used such a service, but it may well be a good move. In my experience, though, having someone proofread the CV is just enough. The last advice is similarly simple, even though less obvious - prepare your resume in advance and always have it ready. You never know when you will have a chance to apply for your dream job and don't want the need to write up a whole new CV to be an obstacle for that. This is not mention the fact that from time to time a friend of yours may run into you shouting something like "We desperately need a good programmer on that project! Could you send me your resume right now?!" More opportunities is better, so be prepared.

As you can see, there is no rocket science about producing a good resume and all of the above advice aligns well with what common sense would suggest. At the same time, if you follow these simple guidelines you will help recruiters and managers spot what they look for in your CV and thus increase your chance to hit an interview.  That's it for this article and I hope that the advice is valuable. If you still have any questions on what to include in your resume, please ask in the comments. If, instead, you have a better idea in regards to what a good resume should look like, be sure to share it here!

четверг, 16 февраля 2017 г.

Search Algortihms in the Real World

In the middle of my university life I had a very strong desire to build a computer game. I was studying for a software engineer and still understood little about most of the software applications. At the same time I loved PC games, which clearly brought me to the idea that I should produce one - the one with the best gameplay, of course. Many of the guys with the same background had that wish and like most of them I didn't succeed.

I spent a fair portion of my free time thinking over the game's design, writing the explanations in a textbook and studying computer graphics. The problem is that in these activities I focused on the things that were easier to comprehend for me. I liked to think through game mechanics - for example the way damage is dealt to the player. I worked this question out on a very detailed level - in many cases descending to the names of C++ classes and of course laying out the calculation rules. With graphics, I focused on trying to make primitives move around the screen using OpenGL, because moving stuff looked like an essential part of game development. This all happened where neither setting, nor even key game features were defined - I hardly settled with the genre. Instead of looking at these high-level concepts of the game, I grasped the details, which I could easily stick into my head, without even understanding what are the key building blocks that I will have to construct a video game from. Speaking in algorithms language, I was doing a depth-first search not wishing too see the entire tree that I will have to traverse eventually.

Recent observations at interviews and during the normal work process brought me to the idea that such a mistake is common among many younger developers. When put in front of an unfamiliar problem they tend to catch some detail that they understand and pursue it to the deep. Because they don't take time to step back and take a look at the problem as a whole, they may end up with weak solutions suffering from various illnesses that happen in the software world. Most likely you will see multiple leaky abstractions and dozens of lines of ad-hoc code in the programs produced this way. And of course don't be too optimistic about finding there clearly separated layers, constituted of the objects that comply with Single-Responsibility Principle.

After acquiring reasonable development experience we tend to replace the depth-first strategy with the breadth-first search. This happens not only because older developers are slower beasts, but more due to the acknowledgement of importance of the full context for the correct solution to the problem. The mistakes committed earlier make us approach both high- and low-level decisions with great respect to the surroundings and see the drawbacks of diving into details before thinking of the solution as a whole.

This obviously makes a lot of sense when we speak of software design and architecture definition, but actually the same breadth-first strategy is applicable to such activities as coding and bugfixing. For example, when analyzing a bug it is tempting to follow the first breadcrumbs seen in the data in an attempt to understand the issue, but this way one may end ep trying every possible hint and spend hours exploring dead-ends. Alternatively, one may take time to fully understand the context of the issue, appreciate its complexity and collect as many facts as possible before even trying to make assumptions regarding the cause of the problem. In this case he will be able to see clearly which guesses are worth a deep investigation and which can be ignored altogether.

There is a similar situation with, for example, writing blog entries. For some people it is natural to produce a good article  simply by letting their thoughts flow onto paper. For others producing a reasonable piece of writing requires planning it and doing a couple drafts first. I don't belong to the first kind and going the depth-first way always results in frustration and wasting lots of my time on a couple short paragraphs. To be honest, sometimes its very hard for me even to produce the first draft from the start to the end - details kill me on the way. Instead, I begin with a rough outline consisting of several key points, then gradually add several sub-points to each of them. Only after this two-tier plan is there, I would start expanding the sub-points to rough sentences, which make a foundation for the draft. This looks very much like traversing the tree of the future blog post with the breadth-first search algorithm, except for the fact that here nodes and leafs are themselves created by the search process.

While I have enough development and writing experience to understand these things, sometimes I still find myself using the details-first approach where breadth-first search is more appropriate. To some extent, this happens because there is always eagerness to produce results and the depth-first path always seems short and clear - until you start going. But at the same time, it may be the case that in absence of the right words to distinguish the two strategies nothing forced me to make a conscious choice - the analogy with the search algorithms came to me only recently. In addition to making the choice clearly visible, it also brings the criteria for picking one of the two approaches. When you need to devise a good solution or just to understand a large and potentially complex problem, breadth-first search will work better - the theory says it guarantees the best result possible. If, however, you need the result early and don't care about its quality too much - for example when building a quick prototype to get an idea of the look and feel of a future product - you'd better use the depth-first search, as it usually yields faster. Sounds obvious, but somehow just having this analogy with the algorithms world in mind seems to make the task of selecting the right approach to any problem easier.

понедельник, 16 января 2017 г.

My 2016 Management Reads

It's the middle of January, so everybody must have already published their version of summary for 2016. I will try to catch this leaving train and list several of the books that I read last year and found particularly useful for everyone whose job involves management. There are actually only two items that are directly related to management, but I still believe that all of these books are particularly useful - sometimes even essential - specifically for those of us, who hold responsibility for guiding others and tackling a wide range of organizational problems. At the same time, all five titles will likely be interesting to any human, no matter what they do for a living.

Dale Carnegie - How to Win Friends and Influence People

This widely known piece of wisdom is among the most precious jewels which I found last year. The stakes are high you read it long ago - I'm unhappy I got to it this late. Even if you did, it may be a good idea to refresh it in your mind. Speaking on the way one should treat people to build lasting and fruitful relationships, the book is crucial to study for anyone, whose job is to lead people, communicate the goals of an organization to them, help them acknowledge their mistakes and grow professionally. The things that I learnt from it helped me provide clearer feedback to the members of my team, understand better what my bosses want from us, explain to the team our objectives and overall build trust-based relationships with the people I work with. To be honest, when I first heard about the book I thought it must be a box of dirty tricks that allow one make others do what they please. In reality it turned out to be a pretty sincere practical study of the principle "treat other people the way you want to be treated" and its implications, touching on many strings of the complex nature of human's ego.

David Allen - Getting Things Done

While it's difficult for a book to compete in value with How to Win Friends and Influence People, David Allen's guide to personal efficiency certainly manages to do so. My regrets about reaching it only in 2016 were even stronger than with Carnegie. The book doesn't touch a lot on the topics of managing people and business, but rather dives deeply into the problems of managing oneself. However, personal efficiency of a manager is a key to the efficiency of his team. The fact that the book not only gives advice on how to get productive, but also inspects many psychological questions around succeeding at one's job makes it a must read for every manager in the world because this way it shows how you can teach your directs to succede. Besides that, the key focus of Getting Things Done is the way one manages information, ensures that progress is made on every active goal and validates the goals themselves. This sounds a lot like the responsibilities of a software development manager, so it will be educating for everyone holding such a position. If you feel almost sold, check this article where I sum up my takeaways from the book.

Nassim Nicholas Taleb - Antifragile

The next book could win the "Most Controversial Reading" award if I made a kind of Oscar for the things I read. The Taleb's style of writing as well as his intense reproaches toward certain broad categories of people and fields of study sometimes bothered me a lot. On top of that, the book is not concerned with management in any particular way. At the same time, the ideas given in Antifragile have a lot to do with change and risks and how we can live with it - the topic that is very relevant for managers. Taleb speaks a lot about the ways one should chose what to invest in and how to secure yourself from unnecessary risks. Most of his ideas are applicable to any area of life, including software management where one frequently faces the need to chose from a wide range of technologies, projects and potential employees. Even if it is difficult to perceive the book as purely practical and career-boosting it is certainly educating and offers fresh points of view.

Cyrill Northcote Parkinson - Parkinson's Law, and Other Studies in Administration

This is another classic that I checked in 2016 and one more must read for everyone involved in any kind of modern organization - no matter what's its size or which role you hold in it. In a grotesque form, looking very much like a collection of unreal anecdotes, the book shows how organizations tend to lose efficiency. It is a great fun to read in the first place, but its anecdotes do show real threats that a company or a team may face. Beside telling how things can get bad it describes quite realistic indicators of the fact that something unpleasant is already happening. Thus, in addition to entertaining you, Parkinson's Law will help you assess the state of your organization or spot the moment when it takes the wrong turn.

Ichak Kalderon Adizes - Management/Mismanagement Styles

Finally, because the article is supposed to list the books I would recommend to managers, there should be at least one that has the word "management" in its title. Management Styles is the first book by Adizes that I read and it looks like the right pick. It provides a great model explaining what managers should do, what they actually do and why these are different things. The focus of this part of Adizes' writing is what kind of managers are encountered in the wild and - especially useful - how most of them fail at their duties. It actually gave me a framework that allows to remember that there are several areas in which I should work and makes me spot my own deficiencies when I fail to pay enough attention to one of them. While this was most valuable for me, the book also covers many aspects of managers' and non-managers' behavior and helps handle colleagues better and know what to expect from them. I definitely recommend it to everyone and will myself study other works by the same author - there is likely more great advice to find.

These five titles played a great role in my personal development this year. Of course that's not enough to satisfy one hungry for growth, so there are lots of articles and other sources of valuable information, like podcasts, but these are a different story. As for the books, in 2017 I certainly resolve to read more than last year and will start with Herding Cats by Hank Rainwater and some other book by Ichak Adizes. If you read one of these, please share your thoughts and takeaways in the comments. In this new year I wish you more great books, that will both entertain and educate you!


вторник, 20 декабря 2016 г.

Interviewing Developers: triggers, part III

The series:
Interviewing Developers
Interviewing Developers: triggers, part I
Interviewing Developers: triggers, part II
Interviewing Developers: triggers, part III

This post also appears in my other blog.

In the two previous posts I focused on certain behaviors of an interviewee, which may indicate problems with their ability to become a good developer in my team. I covered quite a lot of such aspects that push me towards saying "no" and now it's time to show that I can be positive as well. Positive triggers also help conduct an interview, although rarely shorten it, because they make you eager to speak more to the person. In this post I will list some things that make a good impression on an interviewer, explaining why they are good and thus showing what I look for in potential hires.

Candidate: "If you're interested, I'd like to explain the broader context of my previous job / project / task"

Just basic politeness and showing awareness of the fact that the interviewer may have their own plan and time limits change a lot. However, combined with a person' willingness to share his or her specific past experience it is even more powerful. In many cases an interviewer has to spend a lot of energy to get a reasonable picture of the candidate's background and has few options other than squeezing the bits of information out of the person, so one who offers a clear explanation themselves makes a head start. This positive impression may be further amplified with occasional dives into technical details - for example, down to a brief explanation of a class hierarchy - because this likely indicates both an ability to communicate efficiently and a desire to dig into things and understand them. Finally, note the initiative - sometimes it might be the most important aspect of a future employee - it means they have ideas and fuel to make them happen and your organization will only have to stir them in the right direction.

Candidate: "So we stick that thing into that stuff and …"

This one may sound unprofessional and stupid, but trust me, an ability to explain complex technical constructs using the simplest common language terms (yes, I qualify "stuff" for a term) usually indicates that the person does understand the solution being explained very deeply. Of course, whether you understand what they are telling or not makes a lot of difference and I speak only of the case when that explanation is comprehensible. If it is, you will likely find that it is easy to discuss both the edge cases of the same problem and similar but less familiar issues with the developer. That happens because a person using less formal terms in their speech has already internalized the knowledge being communicated - not just remembered some bits about it - and can play with his or her mental model to adjust and adapt it for other scenarios. This trait of a powerful mind is something that you would terribly like your teammates - especially, developers - to have.

Candidate: "Polymorphism is <reasonable explanation>. Imagine we have a base class called Person…"

Bless the people who provide examples for abstract ideas without being asked directly! Examples help every party involved in communication understand the topic better and spot new questions and ideas. While this merely makes the task of answering an interview question easier to do right, the real value is that the person shows that they are able to see the implications of an idea and view it from different angles. A developer who quickly comes up with examples and tries to view a problem or idea in concrete figures usually thinks realistically and understands the context better. Such a person quickly grasps the real world problems that a piece of software tries to fix and can transfer this understanding to their colleagues. As for an interview, they try to make it easier for you through their usage of examples and this alone deserves some respect.

Candidate: "We were using ASP MVC 2, which is kind of old, so I decided to learn Node.js and built a personal web-site / game / whatever with it"

Here I barely need to explain anything: desire to learn and develop on one's own is what makes great professionals. They also don't blame their boss or organization for not giving them an opportunity to learn new things or work with the hottest new technologies - they simply learn whatever they find appropriate when they feel a desire to do so. On the other side, any developer may occasionally get a bit tired with their day job and issues associated with it. A person with a positive attitude feeling their own responsibility for their growth will be able to help themselves through such uneasiness by means of a personal project. It is true that such a side activity may distract someone from their job, but the stakes are high it would rather improve the way the developer attends to their duty giving them extra energy and ability to bring new ideas from the outside world.

This is far from an extensive list of positive interview triggers and there are dozens of things that will make an interviewer like a candidate. Still, I will stop right here, because the things said are enough to give a good indication of what I value when sitting on the hiring side. I must have highlighted this a thousand times, but any hiring decision is based on a lot of factors and no single one of the triggers that I mention should be treated as a basis for yes or no. Still if you have a collection of such triggers in mind they may help a lot navigating you through the process of acquiring a new team member.

An interview is about finding a great person to close a gap in your team, so it is important to note both positive and negative edges of the candidate's personality. The goal is to check whether the candidate is a good fit for the open position, the team and your company's culture - that's why I pay that much attention to the communication abilities and personal traits. Of course, the most important purpose of the interviewing process is to avoid hiring the wrong person - hence the relatively large number of negative triggers in the previous posts versus few positive ones in this one. At the same time, noticing the good aspects is also important - especially when these show that after being hired the candidate will keep growing professionally, help others and improve the way they and their new team do the job.

In conclusion of this short series I wish you good interviews - on both sides of the process - and welcome you to share the bits that help you learn more from them!

четверг, 8 декабря 2016 г.

Inerviewing Developers: triggers, part II

The series:
Interviewing Developers
Interviewing Developers: triggers, part I
Interviewing Developers: triggers, part II
Interviewing Developers: triggers, part III

This post also appears in my other blog.

Last time we looked into several responses that I don’t like to hear during an interview. In this post I will add more examples of candidates’ phrases, which usually indicate weak potential for becoming a worthy team member. Next time, to finish on a good note, I will switch to positive interview triggers, but today let’s keep a bit negative.

Candidate: “I’m tired of writing code. I want to be an architect in your team.”

The funniest thing about this is that I usually hear it from 23–24 years old guys, who have at most a couple years of commercial development experience. It is clear that a candidate with this kind of background is hardly fit for a software architect’s position, but it is also difficult to consider them as a developer because they admit they don’t want to do programming anymore. What’s worse, I believe there are few (if any) good architects who don’t wish they could spend more time coding. Somehow the love for programming comes together with good software design skills and the lack of it means one can’t go far on the technical side of the software development world. The simplest rule here is: never hire for a knowledge-based position someone who doesn’t like its core — they will likely be both inefficient and dissatisfied.

Candidate: “That wasn’t my responsibility”

Usually this comes in response to questions like “Why did your team chose to implement X and not Y?” and “Why did you use that framework instead of this one?” If we speak of junior and mid-level developers we indeed must assume that someone else was in charge of making both product and technical decisions, but it is also true that good developers usually care enough about their work and team. This means they do question the decisions made by the team or the company and try to understand the reasoning behind them instead of blindly doing what they are told. It is also common for them to say “we” about the team — even after they left it — and assume some responsibility for its results. If a person does otherwise, it may indicate a lack of curiosity and ambition, both of which are crucial to becoming an effective team-player and growing one’s skills with time.
Candidate: “I was good but the other developer made incorrect decisions and so we failed”
This one is a refined version of unwillingness to take any responsibility — particularly, for failures. I bet, when asked about the reasons behind one of their successful projects that same person will claim full credit for that success. The problem is that such a person is likely a poor team-player. Clearly separating oneself from their team instead of saying “we” tells a lot about the person’s ability to make the team more effective, collaborate and help others. I definitely don’t want to hire someone who will do poor job and then blame the whole world in their failure — such people learn little, don’t work very hard and thus rarely succeed. Moreover, blaming others doesn’t make you look reliable and trustworthy — even outside the interviews.

Interviewer: “Which of your recent achievements make you feel proud?”
Candidate: “There wasn’t anything like that — just common work.”

While treating this response in a strictly negative way might feel too much, it is nevertheless very informative. Even with purely routine work a good employee will discover a way to optimize his day-to-day duties and will feel proud of doing so. The same way, even people who truly believe that they are inferior to others and the results of their work are flawed will likely find something to be proud of if they are willing to assess their achievements. Conversely, candidate’s inability to identify something worthy among their results means they are unprofessional, because a professional always reflects on what they do, looks for ways to improve that and definitely has a thing or two to name as their valuable accomplishments. You don’t want to deal with someone who shows little initiative and lacks a purpose, do you?

In these two posts I tried to outline possible characteristics of a person I wouldn’t want to hire. Like I said before, neither of the triggers mentioned in this or previous post can make me reject the candidate — they only give me a hint on what to look for and which skills and aspects of personality to analyze. It helps spend less time on interviews and also allows me to maintain a clearer understanding of the traits that I expect and don’t expect from the great developers, QA engineers and analysts we are looking for. I promise to return with a more positive attitude in the next post and review the behaviors that make candidates look good to me.

четверг, 24 ноября 2016 г.

Intervieweing Developers: triggers, part I


Recently I explained the key principles that I follow when interviewing developers, but didn't cover an important aspect - the triggers that may significantly influence the flow of the interview. The trick is the more you do interviews, the better you deduce the character of a candidate from some of their behaviors. In particular, I certainly learned to notice particular responses that the candidates we don't hire may give. Even though one can't base the final decision on a single phrase, these triggers may both save some time and allow to avoid fatal mistakes. To begin with, here are 4 phrases that I heard from some developers.

Candidate: "Normally I work in IDE, so I can't solve this exercise on paper"

I've seen this one several times and it always came as a surprise. Yes, we love paper-programming! We ask quite some practice questions, but hardly ever give the candidate a laptop. I acknowledge that developers rely a lot on the comfort of IntelliSense, ReSharper and ability to run the code and tests that a laptop with an IDE provides. At the same time, offering to do an exercise on paper we want to check certain things about the candidate and refusal to undergo this check is what brings me closer to rejecting.

The idea behind coding without an IDE and compiler is that it allows us to see how a programmer makes assumptions about their task and tools and acts under a healthy portion of uncertainty. In other words, paper-programming focuses more on how you think and approach programming, than on your ability to brute-force the solution by trial and error. I interpret such a dependency on one's tools as unwillingness  to think and work under unfamiliar conditions, which for me means being unable to adapt to temporary difficulties and generally far from what we call a professional.

Candidate: "It doesn't matter that I can't solve the dumb programming exercise - I am good at real problems!"

Here it is dead simple: no, you aren't. Not unless you can show that and the "dumb" exercises are here exactly to allow you to do that. The purpose of sample problems is to verify certain skills. that we expect our potential employee to possess, and to see what kind of mistakes they make. If a person fails at this it doesn't mean we won't hire them - in many cases we spot what we need even behind a failure. But if someone tries to sell us the idea that, while they can't solve our mostly simple tasks, there are some mythic problems that they address easily, that is a sign of a phony, who speaks a lot, but does little. I don't think that loud yet empty bragging is characteristic of a great developer, be they junior or senior, - I believe they either succeed at a task or accept the failure and use the discussion to analyze their solution and spot mistakes there.

Candidate: "I don’t remember the theory - it's only practical considerations that are important"

It's not that our job is about reciting some "Introduction to OOP" book to each other, but it certainly hurts when people respond this way to a question like "what polymorphism stands for?". I expect some respect for the theory simply because it helps do our work better choosing the most suitable solutions and gives us a language to communicate with each other. Because the questions I ask are quite basic, those who fail to answer may have difficulties understanding software requirements and commit stupid mistakes. I'm pretty sure that someone who doesn't remember the key principles of OOP or can't explain the internals of a hash-table from the top of their mind can do good as a developer, but not when they denounce knowledge. Here, in addition to an attempt to gain my confidence by empty talk, I see reluctance to learn, which means I would have to invest a lot of time and effort into bringing the person up to the team's pace and establishing communication with them - the time and effort that I likely won't have.

Interviewer: "Could you please elaborate the answer and explain your reasoning?"
Candidate: "I just think that's the correct answer"
Interviewer: "What makes you think so?"
Candidate: "I just think so"
I was very surprised when I had this dialogue for the first time, but it was real and happened to me more than once since then. Sometimes I meet people who just come across a thing that looks like an answer to the question and try to sell it to me as though that's simply the answer that I need. As I must have repeated several times already, I am looking at the person's reasoning and striving to understand them better - not just trying to check whether they are able to guess a number. Even though it makes me feel somewhat stupid, it's not even the fact that this dialogue comes after I give some hints to indicate that the answer is incorrect that is most annoying. The problem is that such attitude shows that the candidate is bad at explaining their solutions and will hardly be able to contribute to a discussion of a complex problem with their ideas, not to speak of guiding other programmers and any kind of seniority. Even worse, like all the phrases above, this one is a sign of refusal to exercise one's brans - a very unlucky feature for a developer.

As you can see, these triggers show something about the person's approach to solving problems - not about which technologies they know or what tools they mastered. I pay that much attention to this aspect because it is relatively easy to teach a curious and thoughtful programmer a new language or a nice trick, but way more difficult and unrewarding to attempt raising a good developer from a person who doesn't want to study and sometimes even to think.

Even though hearing any of these phrases doesn't mean I would instantly stop the interview and refuse the candidate, they greatly impact the outcome of the interview. I have seen other managers hiring people who failed to solve an exercise or answer a couple questions and did that myself too. Still, I haven't yet met a person who behaved in the manner described above during their interview, but gave enough reasons to hire them nevertheless.

There are a couple other ways in which a candidate can draw my attention - both in positive and negative ways. I will get back to these in future posts. In the meantime, what do you think of these triggers? Do you believe they are valid or should interviewers be more forgiving?