Sergey Maskalik

Sergey Maskalik's blog

In the pursuit of mastery

Atomic Habits

I really enjoyed this book, and I would highly recommend it to anyone who is trying to work on something that requires a lot of effort. By establishing tiny, incremental improvements in our lives, the benefits will accumulate and grow, like a financial investment. Eventually the investment will reach a critical point, and you will see a massive change. The author, James Clear has an interesting solution on how to form a habit, you want to make a daily task super easy. For example, if you are trying to be a more consistent writer, your initial goal would be just sitting down to write for two minutes every day until you’ve established a habit. Only after you’ve made it your habit to write a little bit daily, can you progress to increase the difficulty of the task..

The entire book is full of many other great techniques and stories. After implementing the author’s suggestions in my own life over the last month, I can already tell that they work better than pure motivation. There were many days when I didn’t feel like performing the task at all, but by just telling myself that it’s super easy and it would take just a few minutes, I was able to complete it. I’m looking forward to continuing to work on building my habits, and if my writing habit works, I will report on the progress.

A Guide to the Good Life: The Ancient Art of Stoic Joy

This book was highly recommended by Tim Ferriss on his podcast, and it quickly became one of my favorites. Stoic philosophy provides ancient wisdom that is still relevant today. It explains that without a coherent philosophy of life, humans are more likely to default to pleasure maximization and distractions that will lead to squandering time, or worse, pursuing something that would not fulfill us in the end. Because Stoic philosophy is based on logic, a lot of it makes sense and does not require you to believe in something abstract or intangible.

Stoics believed that the key to happiness is to prevent ourselves from taking for granted things that we already have. Because a lot of human unhappiness comes from a desire to have more, if we practice appreciation for all the things we worked so hard to get, we can trade desire for enjoyment. In addition to being grateful, another technique would be to imagine losing the things that we already have. This would also make us appreciate our existing situation and not take things, relationships or our health for granted.

Another great piece of wisdom that I really enjoyed was the importance of setting achievable goals. Achievable goals mean, if I play a tennis match, winning the match would be outside of my control, and therefore would not be an achievable goal. Why? Because I cannot control my opponent or the environment; for example how good of a player she is, or if the sun is in my face. Rather than focusing on winning the match, my goal should be to play at the best of my ability, whichis something I could certainly achieve. By setting achievable goals, we prevent ourselves from getting disappointed and as a consequence discouraged and frustrated. In Stoic philosophy achievable goals are also called internal goals, versus external goals something that I don’t have control over.

I hope you enjoy this book as much as I did and that your life will be more joyful and fulfilling.

C++ Crash Course

After more than a decade of working with managed, high level languages, I needed to work on a cross platform project written in C++. I quickly discovered that it was hard to find a good reference on modern C++ without it being too overly complex or having to learn previous versions first. This book filled the gap that I had, and I would highly recommend it to any experienced programmer picking up C++ for the first time.

Flour Water Salt Yeast: The Fundamentals of Artisan Bread and Pizza

I give this book honorable mention because after reading it, I was able to consistently bake great tasting and looking bread. I love my carbs and a lot of times bread bought from the store does not satisfy me. If you’ve never baked bread, it is a great exercise where you can step out of your comfort zone and practice your beginner’s mind. It was also fun learning about the fundamentals of bread baking, with its different flower types, fermentation, and hydration.

bread picture

I’ve recently updated a tiny utility script (sqsmover) that I wrote when I was learning Go Lang that moves AWS SQS messages between queues. After three years, it is still a userful tool when I need to move messages between queues. I feel like it could be useful to others who use SQS and deadletter queues because at one point something is going to fail and your messages will end up in the deadletter.

In order to polish it, I’ve included the following features:

Help menu

sqs mover help menu

Region flag

Original version had region hardcoded in the code and needed a code change if you used a different region, oops. I’ve modified to allow region to be overwritten as a command line flag and default to us-west-2.

Installation

Updated installation instruction with one line shell script install for macOS, Linux, or OpenBSD! And compiled binary for Windows. No longer in order to install the app you have to have Go Lang installed locally and issue a go get ... command. This was pretty easy to do with awesome goreleaser project and companion godownloader. GoReleaser automatically creates binary releases and publishes it to github while GoDownloader will create a bash script for one line installation.

Intuitive error messaging

It sucked when your script fails and you don’t know what went wrong, so I’ve included a lot more user friendly error messages that should help users with figuring out what needs to be done.

error

Progress indicator

For the first version app I used to just output every message moved to the screen. This is not very useful if you have thousands of messages. A better user experience is to include a progress indicator.

progress indicator

Future work

At the moment the utility is using a batch download and upload which moves about 10 messages at a time. It’s pretty fast if you need to move few thousand of messages but if you have a million stuck in the deadletter queue I could imagine it could take a while. To speed up, I’m thinking to introduce multiple receiver and consumer threads and allow users to specify how many threads to use.

That’s it let me know if you come accross any issues using github, thanks!

When used to best advantage, exceptions can improve a program’s readability, reliability, and maintainability. When used improperly, they can have the opposite effect. - Joshua Block

Most of this wisdom comes from Joshua Bloch’s Effective Java book, see the book for the complete discussion on the exceptions.

Use exceptions only for exceptions conditions

// Horrible abuse of exceptions. Don't ever do this!
try {
  int i = 0;
  while(true)
    range[i++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
	...
}

Better idiom for looping through array is: for (Mountain m : range) m.climb();

  • Because exceptions are designed for exceptional circumstances, there is little incentive for JVM implementors to make them fast as explicit tests.
  • Placing code inside a try-catch block inhibits certain optimizations that modern JVM implementation might otherwise perform.
  • Exception based idiom is much slower than state checking.

A well-designed API must not force its clients to use exceptions for ordinary control flow

Throw exceptions appropriate to the abstraction

Problems when a method throwing an exception that has not apparent connection to the task it performs, usually propagates by lower level abstraction.

  • Pollutes API of the higher level with implementation details
  • If implementation of the higher layer changes, the exceptions that it throws will change too, potentially breaking clients.

Higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction. This idiom is know as exception translation.

// Exception translation
try {
   httpClient.execute(...)
} catch (IOException e) {
   throws PspApiException(...);
}
// Exception chaining (special form of translation)
try {
   httpClient.execute(...)
} catch (IOException cause) {
   throws PspApiException(cause);
}

class PspApiException extends Exception {
   PspApiException(Throwable cause) {
      super(cause);
   }
}

While exception translation is superior to mindless propagation of exceptions from lower layers, it should not be overused.

  • Use validate params
  • Deal with exceptions on lower level

Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.

The cardinal rule in deciding whether to use a check or an unchecked exception is this: use checked exceptions for conditions from which the caller can reasonably be expected to recover.

Use runtime exceptions to indicate programming errors. Great majority is precondition violation, a failure of the client to adhere to the contract established by the API specification.

Because checked exceptions generally indicate recoverable conditions, it’s especially important for such exceptions to provide methods that furnish information that could help the caller to recover. For example, redemption of the card has failed because there is no money left, that information could be relayed back to player.

More on where to use checked vs unchecked.

Avoid unnecessary use of checked exceptions

Overuse of checked exceptions can make an API far less pleasant to use. Forces caller to handle the exception.

Burden is justified if the exceptional condition cannot be prevented by the proper use of the API and the programmer using the API can take some useful action once confronted with the exception. Unless both of these conditions hold, an unchecked exception is more appropriate.

Favor the use of standard exceptions

IllegalArgumentException (Non-null parameter value is inappropriate) IllegalStateException (Object state is inappropriate for method invocation) NullPointerException (Parameter value is null where prohibited) IndexOutOfBoundsException, ConcurrentModificationException, UnsupportedOperationException

Document all exceptions thrown by each method

To use a method properly you need to know about exceptions that it throws, therefore, it is critically important that you take the time to carefully document all of the exceptions thrown by each method.

Always declare checked exceptions individually, and document precisely the conditions under which each one is thrown using the Javadoc @throws tag

Unchecked exceptions represent programming errors so it is wise to document them so programmers get familiar with all the errors so they can avoid it.

If an exception is thrown by many methods in a class for the same reason, it is acceptable to document the exception in the class’s documentation comment.

Include failure-capture information in detail messages

To capture the failure, the detail message of an exception should contain values of all parameter and fields that “contributed” to the exception.

public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
  // Generate a detailed message that captures the failure
  super("Lower bound: " + lowerBound + ", Upper bound: " + upperBound + ", Index: " + index);

  // Save failure information for programmatic access
  this.lowerBound = lowerBound;
  this.upperBound = upperBound;
  this.index = index;
}

Don’t ignore Exceptions

An empty catch block defeats the purpose of exception.

Exceptions code smells

try {
   // 100 lines of code
  ...
} catch (Exception e) {
  //Something failed.. not sure what or where, is it important or is it a bug, who knows ¯\_(ツ)_/¯
}

Ideally try catch around the line where exception is expected or a few lines to make the code more readable.

Catch all unhandled exceptions in the global error handler and log

Unhandled exceptions indicate programming errors, most likely the API was not used correctly and that’s a bug that could be fixed