Tuesday, March 08, 2016

What?! Pre-interview code challenge?!

It doesn't matter how many years of experience you have, how many coding challenges you've solved in your spare time or how many open source contributions you've made, companies still want you to complete their tests or coding challenges. We can debate it but there's very little we can do about it.

But then I bumped into a new beast - pre-interview tests. You write a coding challenge in order to secure an interview. In other words, don't bother to send in you resume unless you spend several hours writing a program. And as in this instance (I'm not going to disclose the company's name) they ask you to make it public on github. Great idea ... if you want to analyze other people's approach :-) And that's what I did.

After analyzing several repositories I found a few patterns. Their common denominator is:

People don't really read requirements.

And here's why.

  • The code should be written in Java but you can see people trying to outsmart by providing Python, Go or Haskell version. It may be fine as a supplemental implementation to impress the recruiter but not on its own.
  • None of the implementations I could check came with any tests at all! Unit, integration, anything. That's a very bad sign. Although I personally don't advocate TDD I still think that tests are important, especially when it comes to coding some system logic. They also speed up the development cycle as you don't need to build and run your application just to check it the code works.
  • Although people were asked to structure their application as if it was a production grade application some still put everything in one class.
  • Missing documentation. At least javadoc, better yet stand alone handcrafted document outlining how the application works.
  • Build instructions. People rarely bother to write quick instructions about how to build the application. Although it may be clear that gradle/maven has been used it's still nice to provide this in writing.
  • Some assume that a CSV document can be created with simple List.join(",").
  • Some even assume that parsing JSON means splitting a string by ,.
  • People ignore application return values. They just spit out an error message and bail out (so the return value is 0 indicating successful completion).

Advice to people applying to those companies. It's unlikely you're the first one applying. Search github, bitbucket, gitlab and the likes. That can give you an idea about your competition. It could also help you out with your code should you get stuck.

And a closing message to companies trying to make it easier for them by asking people to write code before applying. Asking people to code first, massively limits the pool of people applying. There are thousands of great developers who don't want to spend hours coding just to wait if you come back to them. I'd also say that it attracts wrong kind of people.

  1. people who like to solve challenges and have time to do that but are not really into a long term relationship
  2. people with little experience hoping to skip the line
  3. cheaters who smell a chance of landing a job

I still think it is much better and efficient to do a quick screening (via skype or the likes) and ask a candidate to join you for a day (preferably pay the person for working with you that day).

Friday, February 12, 2016

A farewell to Node.js ... for now

It's tough. Choices have to be made and decision taken.

After spending years experimenting (and even professionally working) with Node.js I think it's time to say farewell and thank for all the fish.

Why?

There's several reasons but the main for me are:

Asynchronous IO is tough. Really tough. Callbacks, Promises, Async/Await all that stuff. Sure, Async/Await will make this easier but under the bonnet it will still be async. I think the cause of this is that we think sequentially - do this, do that do something else. Not do this for user1, do this for user2, do this for user3, do that for user1, do that for user2 ... The fact that we serve several users at a time doesn't have to be reminded to us all the time.

Debugging and testing is pain with callbacks. As async functions are normally executed in their separate threads you lose continuity when your functions resumes. It's hard to track down where you'd been before the callback got called. And simulate callbacks in unit tests doesn't help either.

Dependency management. NPM everywhere. Node.js doesn't have its own packaging, module system and relies on NPM to do the hard work. Problem with NPM is, that if package A depends on package B and that depends on package C it's all nested and not reused. That means, you can end up with hundreds of packages C in your project. I still remember my Ghost blog project. It downloaded 500MB of NPM modules just to run!

Spartan core libraries. Node has very limited number of standard functions. It means that even for simple tasks like working with dates you have to turn to libraries like moment.js. Most of the stuff you can find in standard libraries in other languages needs to added as a dependency in Node. So you always facing decisions like `lib1 has these features but lacks some other` so you mix and match all the time to get basic stuff done.

No opinion. We all know that today's patterns and best practices are tomorrow's anti-patters. But this cycle is massively accelerated in the Node.js world. Grunt, Gulp, NPM. This is rapidly changing and there's no sign of consolidation. It's hard to operate in a world where tools are discontinued on a daily basis (with no replacement). Node needs something that would define and guarantee the basics so you can focus on programming and not worry if your code will be buildable in a year's time.

No explicit types. We can probably debate this for ages but as there's no way to enforce types (at least optionally) it's very hard to define contracts between libraries and their users. There's nothing that would warn you that a return value can't be assign to your variable. Or calling a function isn't possible because of incompatible types. That puts extra pressure on library authors to well document their code so the types are documented, somehow.

To sum it up. On front-end I'm left with no choice - it has to be JavaScript or transpiled JavaScript. For backend though, I stick to something else.

Wednesday, February 10, 2016

Striking the right balance

We all know that software can be really complex. Software solves complex problems and needs to be complex. Period. But when it comes to our toolkit we should always prefer simple, streamline solutions.

Software development can sometimes morph into some kind of competition. Some developers and sometimes whole development teams can turn into macho style super heroes producing pretty complex code just to show the world how good they are. So you want an example - look no further than AngularJs. That's what happens when smart guys over-engineer their solution.

Dependency injection for a functional language? Services, providers, factories? Parsing function bodies to figure our parameters? You get all this and more. The question is why? Functional languages always prefer explicitness before implicitness. Functional approach tries to eliminate auto-magicalness. And why have so many service types? Who needs to use magic string constants to describe what a directive can be applied to? Yes, we know the guys behind Angular are smart but do we need to worship them everyday?

Again the same story. All you get is something to learn. And once you learn it you the guys release version two do zero with no backward compatibility. And you start over again.

On the other end you have things like Hazelcast. You don't need a diploma to use it. You plug it in as a library or use it as stand-alone application and it just works. Don't be fooled. Hazelcast is far more complex than Angular. Both in terms of code and the problem area it covers. But the guys there don't try to awe you. And that's the trick. That's why React is so popular.

So the rule is - don't try to convince your users that you're a smart guy by writing complex difficult libraries - convince them (if you really need to convince anyone) with simplicity.

One rule of simplicity is to reuse whatever is out there or at least allow this existing tools/libraries/utilities to be used with whatever you're coding.

Don't be revolutionary - be evolutionary.