Anti features

When evaluating new technology, framework or library; a lot of importance is given to the salient features. While it is very important to know the positives, the negatives usually tend to be glossed over. Being aware of the shortcomings of a framework gives one the ability to anticipate problems down the road.

feedback-3239454_640

For example, let us take NoSQL databases. A lot of time is spent on singing paeans to the scalability, malleability etc of NoSQL databases while hardly thinking about the negatives that come with it.

Two simple techniques which give a good visibility on anti-features:
1. The very obvious one, Google for the shortcomings. Someone would have written a blog post on the interwebs highlighting how a framework or technology let them down. For example, take this post by Uber on how Postgres did not work as expected for them.
2. Comb through Github and/or JIRA peeking at the bugs raised and enhancements requested.

Both of the above will provide a good picture of the shortcomings. If you are evaluating a closed source proprietary technology, the above may not make the cut.

Once a mental note is made of the negatives, ponder on the scenarios where this might affect your usage. It helps to spend quality time on this as this will save one from a lot of future trouble.

If you think about this, this might sound very obvious but tends to be highly neglected. We get so caught up in the positives of something that the negatives tend to be ignored and this usually comes biting us back later.

Build Versus Buy

Consciously or unconsciously, as software engineers, we perennially take build versus buy decisions. It might be as trivial as copy-pasting code from somewhere versus racking up our brains to write our own; using an already available library or creating one from scratch; using a time tested framework against designing one; building a piece of software internally as compared to buying one.

backdrop-21534_640

The way we account for the build versus buy decision varies. Some of the frivolous reasons for building in-house are NIH syndrome, hubris, and planning fallacy. We generally tend to overemphasize our expertise, knowledge, and capability which naturally lead to building internally. Also, we underestimate the amount of work involved in creating software, only once we get our feet wet does the reality set in. A very valid reason for building internally is the cost, but when accounting for cost, we usually overlook the hidden cost of developing software. Buying a software has an upfront monetary cost whereas by building internally we pay in the form of opportunity cost, talent cost, feature cost, etc.

Build versus buy arguments are reminiscent of qualitative speak – “This is not our core expertise, we should be concentrating on solving our business problems”; “This is going to cost us a bomb, let us build in-house”; “We should have had this yesterday, building in-house will cost us another 6 months”; “Will that external product be able to handle our scale”; “Can we trust them with our data”; etc. In most cases, build versus buy decisions are qualitative, it is not an easy exercise to quantify them.

When evaluating a product that is already out in the market versus building something similar, a cardinal mistake people commit is mapping features one to one. Even though having 100 different features looks rosy and attractive, usually we end up using only a select few. Instead of trying to match an external product feature to feature, scope out the features that you need or would probably use and then estimate the effort. Another is refinement. An external product will be refined and polished, but you may not need the same level of sophistication. For example, you might not need a web interface for the product; a terminal would work fine for your use case.

When faced with the build versus buy decision, asking the following help:

  • Is this my core expertise or is it something I can let others do for me?
  • What is the cost of getting this done externally versus hiring people to build this?
  • How much control do I need over this, i.e. can I live with some error, downtime or opaqueness?
  • Will I do a better job building this internally?
  • Do I have the expertise needed to build this?
  • Once I build this, will I be able to maintain and enhance?
  • What is the opportunity cost of having this sometime in the future versus having it now?

Use the answers to the above as a beacon for the build versus buy decision.

Look ma, no schema

Due to the plethora of NoSQL databases available, schema-less is a tantalising option these days. While starting on a new project, NoSQL databases look attractive but reality sets in when the maintenance problems start creeping up later.

nosqlpng

 

If you are doing anything with data, you need to know the schema of that data. What this boils down to is whether this schema is explicit or implicit. In relational databases, the schema is explicit and well documented whereas in NoSQL databases, the schema is implicit i.e it is maintained in code. All the goodies that you get with relational databases like integrity checks, constraints etc should be taken care of in code.

Products go through a multitude of changes, features get added and axed and in order to accommodate this, the schema has to change accordingly. In relational databases, carrying out schema changes on tables with humungous data is a daunting problem which requires considerable planning and effort. This problem is not present in NoSQL databases, but again, you end up managing this in code. In order to handle multiple versions of the schema, code gets littered with if else statements. This gets even more messy as this is spread across the code base in multiple places wherever data is being handled. In relational databases, you handle schema changes once and for all, in NoSQL databases, you continue to do it in code long after the change.

Multiple people work on code at different points in time, people join and leave teams but code lives on. This is when the maintenance problem starts raising its ugly head.

A big reason a lot of startups opt for NoSQL databases is due to the constant flux in these organisations. Requirements change frequently due to which a stable schema design becomes next to impossible. In this landscape, NoSQL databases look like God’s gift to mankind. If your company does not fall in this bucket and you find yourself tempted to use a NoSQL database, take a good hard look at the problem and ensure that it is worthy of a NoSQL database. There are problems which are better solved with a NoSQL database but these are far and few.

Unit test – purist versus practical

building-blocks-615239_640

Whenever you ask a question on unit testing in a forum, there is always that one person whose only job is to point out what you are doing is not unit testing but integration testing. It is important to know the difference but it is more important to not lose sight of the goal, ensuring a reliable and a bug-free application. Also, you need to adopt a terminology that works for you and your team, rather than what purists think or say.

In absolute terms, if a test depends on anything that is not in your control, it is not a unit test. For example, if a method that you are testing uses a public function, a method from an included library, database or an external API, it is not a unit test but an integration test. For a test to qualify as a unit test, you need to mock all these dependencies and get them under your control, only then you can claim your test as a unit test. Now that we have the purists happy, let us move to a more practical worldview.

When a regular joe developer refers to a test as a unit test, what she means is, she is trying to test a functionality in a massive gnarly application that she thinks is a small independent unit. This unit might have some components that are not under her control. Instead of debating whether she is unit testing or integration testing, a better discussion is trying to figure out what is the intention of the test, what needs to be controlled/mocked and not. Helping her to figure this out and achieving this will add more value than debating whether a test is a unit test or integration test.

Selfie

Let us say that you want to execute a job periodically, what comes to your mind first? If you are familiar with Linux, I can hear your screaming cron. Well, no doubt about that, cron is great, but what if I told you there is another approach which you can take to execute periodic jobs? Our good old continuous integration server Jenkins can supplant cron as a tool to execute periodic jobs and it kicks ass in doing so.

What makes Jenkins such a gem for executing periodic jobs?

1. You get a great web front end which is comfortably accessible from the browser.

2. The front end gives you a complete history of the previous runs with detailed information like when did the last execution occur, how long it took, what was the output during this execution, historic trend of the execution time and other diagnostic information.

buildHistory

buildTimeTrend

3. You can leverage the Jenkins plugin eco system and do some nifty things. For example, you can use log parser plugin to parse the execution output and alert if a specific format is found in the output. The great part here is that your job need not have alerting logic baked in, your job concentrates on doing what it does best, let Jenkins take care of the rest.

4. You can configure regular Jenkins build rules like alerting on execution failure, preventing subsequent executions if the current one fails, etc.

5. You can chain multiple jobs and the chain is very obvious thanks to the great Jenkins UI.

All this is great, but one problem I faced with Jenkins is that you cannot have a Job call itself recursively with a delay in between, you have to schedule the job execution using cron expression. The difference is subtle, but there are implications of this limitation which I will expound with an example. Let us say that I have a job which ideally should run every 15 minutes, but sometimes this job execution takes more than 15 minutes to complete, in that case what happens is, job executions queue up and fire successively one after the other. The way I want this scenario to pan out is, once the execution finishes, it should wait for 15 minutes before the next execution starts. I could not find a way to do this in Jenkins and hence selfie was born.

Selfie is a Jenkins build trigger plugin which lets a project to trigger itself after a configured delay. The plugin appears as one of the build triggers while configuring a new project.

selfie

This is my first attempt at writing a Jenkins plugin, pull requests and code reviews are more than welcome.

SQS versus Kinesis

A lot of people are confused between SQS and Kinesis. In some ways, both act as a queue, but there is a massive difference between the two.

SQS is a queue, adheres to FIFO and promises at least once delivery.

Kinesis is a distributed stream processor. A simplistic and hand-wavy way to think of Kinesis is like one large log file; items that you write to the stream as lines in this log file. When you want to process the stream, you get a pointer to the log file. When you read a line from this log file, the pointer moves to the next line. Kinesis is stateless, as in, it does not maintain the pointer for you, it is up to your reading process to maintain this. What this means is that, say you are reading off a Kinesis stream, and your process goes down, when you bring the reader process up again, it will start processing from the start, not from the last line before the crash. There is no concept of popping items out of Kinesis, data is always there(expires after seven days), you manipulate the pointer to this data. Hence, if you want to reprocess the stream, you can replay i.e., you can start from the beginning and do the whole thing over and over again. AWS provides a client library for Kinesis which maintains the state for you. This client library uses dynamodb to persist the state.

This should give you a fair idea of when to use Kinesis and when to opt-in for SQS.

Nothing is sacrosanct

There is an interesting bug opened against Kafka. For those of you too lazy to click on the link and read through the description, I am reproducing it here in full.

It appears that validation of configuration properties is performed in the ConsumerConfig and ProducerConfig constructors. This is generally bad practice as it couples object construction and validation. It also makes it difficult to mock these objects in unit tests.

Ideally validation of the configuration properties should be separated from object construction and initiated by those that rely/use these config objects.

http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/

It links to an article by Misko Hevery on writing testable code. If you have not read posts by Misko Hevery, I urge you to. For an open source project like Kafka, it might make sense(Jay Kreps, the person behind Kafka does not agree with the bug as visible in the comment) to follow all the guidelines of writing testable code but for your project it might not. If you are a small company with a two or three person team, do not blindly follow practices because someone on the internet says so.

Follow rules and guidelines only if it helps you to make your code more secure, performant, easier to maintain etc, do not ape guidelines without understanding why they are laid out in the first place. To go back in history, checked exceptions were all the rage in the Java land a couple of years ago, but these days, after frameworks like Spring sprang up, people look down upon checked exceptions. Same with TDD. TDD was expounded as the next best thing after sliced bread, but now programmers are raising their doubts about TDD.

A lot of times, mocking objects, interfaces etc takes more work than writing the actual functionality. In many projects, there might not be an ROI in writing/maintaining this elaborate test framework/infrastructure. It is true that injecting dependencies into an object makes it easier to test, but it also comes with the downside of having to take care of injecting dependencies every time you create that object. If you are injecting dependencies by hand, object creation becomes an elaborate exercise each time, else you have to delegate this to some framework like Spring, Guice etc, now your project is bloated. Maybe you should side step dependency injection and create the object with the dependencies inside it.

The situations and background under which these rules/guidelines crop up might be radically different than the one in your organisation/team. Taking the call of what to follow and what not to is more of an art than science. Your instincts, past experiences etc help you in formulating them.