Programming is like Writing

Everyone heard that programming is very similar to writing books. “It has many similar traits” programmers think. There is even a thing called “Literate programming” invented by famous Donald Knuth.

But, are there really much similarities between those two activities? Well, except that both require starring at screen and typing a lot of text.

One of my goals for 2017 is to improve at writing texts. I found that there is an increasing need for me to write good texts both at work and for personal needs (like this blog). At the same time, writing is not something that goes for me as easily as coding. To achieve my goal, I’ve started with picking and reading a few books which give advices on how to write texts correctly.

One of such books is “On Writing” by Stephen King. My friend was reading some fiction book written by Stephen King, so I’ve also decided to check what are some interesting books by this author. I must say, that the only book I found the most interesting for me at that moment was “On Writing”. I could have done 2 things in one: finally read some Stephen King book and make a step towards my yearly goal.

I must confess that book was an easy read. It was like a fictional book, but wasn’t. A great example of helpful book that is easy to read. This is due to 2 important parts:

  1. Author gave background stories from his live. First 1/3 of the book is more like a biography of Stephen before he became a famous author. Maybe, it’s because I love to read biographies of famous people, but I’ve finished that part on a single breath.
  2. Every advice author adds also comes with some background story and intuitive explanation. You not only learn good advices, but have a background that helps you remember it once you’ve closed the book.

Among the advices author gave, I have highlighted a few that were, as I felt, most important to me. I’ll share them with you a few moments later. I use some of the advices every time I write a text, like simplification, drafting, and 2nd draft rule to some degree as well.

Somewhere in the middle of the book I had an enlightenment that the writing’s general best practices from Stephen King are very similar to those we follow in programming.

Simplify and remove the clutter

Although some junior engineers love to create overly complicated (they say beautiful, flexible and extendable) designs, over-engineering in architecture and code, experienced software engineers know that simplicity is the only true thing we all must aim.

Software engineers should focus on keeping things simple, both in code and in design. And that’s what author of the book also recommends. Remove unimportant parts that don’t add up to the story, remove overly complicated and unnecessary descriptions, leave as low as needed for the reader to feel the story. Otherwise, 90% of readers would just give up on this boring book.

Not everyone is ready to read 10 pages about the colors of sunset of 20 pages about the architecture of the city. Same in code: not everyone ready to get through 5 page methods, and not everyone is ready to dig deep into the layers and layers of your code.

Avoid passive verbs

The analogy here is very simple:

  1. use verbs for functions/methods names,
  2. put methods into the objects that they related to.

It is not the best sentence “Pizza was delivered to my doors.” Once stop using passive verbs, you get “Courier delivered pizza to my doors.” Way better!

Same in the code: not “pizza.deliveredTo(myDoors)” but “courier.deliverPizza(myDoors)”. That makes modeling object-oriented relationships easier.

Practice Continuously

To become a good author, one should practice continuously, and write something almost every day. For example, Stephen King writes every day. He starts in the morning, and then writes until he reaches his goal.

Same is with coding. You just can’t become a great programmer, if you don’t practice.



Story from my life


Many years ago, I was a kid who wanted to learn programming. The only issue, I didn’t have a computer. But I didn’t get upset that easy, I’ve bought a book about programing on Turbo Pascal 7. That was a book with cover of green and white colors, published by Sankt-Petersburg publisher and covered TP7 from basics to writing code that draws 3D objects and generates audio. I loved that book. It was my first book on programming.

I spent a couple months going through this book: learnt about data types, arrays, pointers, files and many other things. I followed author recommendations and wrote many programs. As I mentioned, I didn’t have a computer yet, so all my programs were on pieces of papers.

But one day, my parents bought a computer. I started porting my programs from paper to Borland Turbo Pascal 7 environment. Only to find that, lo and behold, none of them worked. They even didn’t compile. Boy, was I upset!

I had to spend a few more days to fix some of the programs and got them working. Since then, there were not many periods of my live where I didn’t code for a long time. Because, I quickly realized that practice is the most important part.

For years after that, I still thought the problem was with me: I’m just a “practice” person, not a “theory” man. I learn better and faster from practicing not from reading books. That was a wrong-thinking. It’s not my problem. We all are like that!



If you want to be good at something, practice at it continuously.

Have a place for writing

Authors should have a place where they can hide from everyone and focus on the book. Place, where nobody and nothing would distract you, where things motivates you to do your work the best.

But, to be honest, not only writers need such place. Artists also need a place where they could focus on paining. Designers need such a place too. Software engineers also want to have it in their life; and, ideally, this place shouldn’t be in the open office space.

Sometimes, I imagine my ideal place for programming. It is a large room, with high ceiling, 2 walls are covered completely by bookshelves, another wall has a large glass whiteboard on it. Room has a large desk with large displays on top, and comfortable super expensive chair next to it. There is also a comfy wingback chair for reading with a standing lamp close to it. Right, my ideal “office” is both programming office and small library.

Have a toolbox

Simple here, authors have dictionaries and vocabularies, favorite software to write a book or type of paper and pen they can’t live without.

Programmers have their IDEs, programming languages, version control tools, programs for reading documentation and many many more.

Always do 1 or 2 drafts before final version

Review results of your own work, no matter if it’s code, design or documentation. See if you could improve it, whether it is bug-free and covered with tests. And, once you are fine with the version you have, hand it over for a peer review.

Similar with books: author writes first draft, reviews and modifies it a few times, and once author is ready, book is passed to editor.

Write about something you like

I don’t think any reader would be happy to read what author wrote about a topic author doesn’t like. Author would either make it extremely boring or obviously incorrect. Reader would inevitably feel discomfort reading such work.

Code, that programmer hated to write, would look like… code that written in hatred.

If you want to be successful at what you do, you need to love it. Either it is writing, programming, paining, designing, crafting or counting money.

Read Continuously

Stephen King reads a lot of books. He loves that. And he recommends it to other wanna-be authors as well. Read many different books, see what works good and what doesn’t, learn elements of style from others, and improve your own.

But that advice is exactly same as all programmers receive from their mentors all around the world: read code written by others, study design approaches created by other more experienced software engineers etc.

Summary

Writing good is hard. Coding good is hard.

But there are a few best practices we all can use. There is no magic behind them. They are universal as work for writing, coding, and almost anything else.

These best practices are:

  • keep simple and remove the clutter,
  • practice continuously,
  • learn from more experienced peers,
  • make your work be more comfortable for you to do,
  • love what you do.

Using Mind Maps

Mind maps is a visual way to structure information in a tree like structure. Such maps are convenient way for structuring knowledge, ideas, plans and tasks.

Usually, mind map starts with a root node, which has references to child nodes. References do not have names, but color can be use to code specific subjects. Each node, except root, has a parent node. Child represents some information specific to its parent node. This helps to build a tree of information, that can be easily consumed by human.

I am a big fan of visualization. Good visualization represents complicated things in a simple way that is easy to understand. Mind maps is one of the simplest but effective visualization techniques. It helps me in many different places: from making notes to managing projects.

MindNode

I’ve spent a few days looking for mind map tool that I would love to use. At the end, I’ve picked MindNode, a beautiful tool available for macOS and iOS. It has a few very interesting features that I just love and won’t be able to live without anymore:
  1. There is an app for iOS, so I can work with mind maps using my iPhone and iPad. Experience is very similar to desktop application. Device app works smoothly; I never had issues with creating/updating maps from my phone.
  2. iCloud integration allows me to share maps between devices and computer.
  3. Multiple themes are available by default. Moreover, I can modify existing theme to create my own. I usually use different themes to differentiate different types of maps.
  4. Node can be marked as a task. For parent task, it will convert child nodes into tasks. Parent task can be used to track progress. Tasks mechanism is intuitive.
  5. MindNode allows to attach URL and description to node. It’s possible to create a documentation using mind map; MindNode can easily convert it to Markdown document.
  6. Additional relationship between nodes can be created using links. I do that quite often to connect two nodes that are in different parts of map.
  7. Awesome keyboard shortcuts support: can do most of work without touching touchpad.
MindNode has many more useful features, like: sharing mind maps with others using web interface, attaching media resources to node, exporting map into different formats etc.

Usage

As I’ve mentioned above, I use mind maps for different use cases. Most common are:
  1. building a knowledge
  2. generating ideas
  3. planning and managing projects
Next, I give more description on each of those.

Building knowledge

I found that mind maps work better for me than text notes. It is easier to read mind map: easy to detect most important parts, faster to read map in larger batches, references are an important mechanism to add extra dimensions to data. It is possible to collapse graph to see only the most important parts, and if need, dig deeper for more insights. Branches have different colors to separate them visually.

It is often hard to structure new mind map in the best way. I usually start with something that works right now, and do refactoring once gathered enough information, and there is a need in a new structure.

For me, map is a better way to collect and hold my notes. Before, I usually collected notes for each source of information (i.e. had different notes for different books). Therefore, it was hard to get through and find useful information. Things changed with mind maps - I collect knowledge per subject. For example, I have mind maps for such subjects as “Software Engineering”, “Writing”, and “Machine Learning”. I update those with facts, ideas, and best practices.

Here is example of my mind map for Software Engineering (all branches are collapsed for better visibility):



One of its sections focuses on making projects in a right way:



Such maps usually contain a branch for subjects that I want to research next. Those are represented as tasks, and help track my work on improving my knowledge base, follow up on missing parts etc.



Generating ideas

When working on new projects, it is important step to generate ideas for features, approaches and solutions etc.

I also found mind maps are quite helpful in this realm. When I need to brainstorm features, I start with a node “Features” and add child node for each high level feature. Afterwards, I extend feature node with more details and clarifications using its child nodes and so on and on.

Here is an example of features ideas for some service that I was scoping before. I start with some high level feature description, like “Integration with other tools”, and then move forward to clarify and add details.



And again, branch to track work on further research is a must:



Planning and managing projects

Most of the projects that I start nowadays begin with a new map in the MindNode. Map consists of the main parts: design, risks, scope of work, and plan of work.

I usually don’t go much into details in the map; I use another tools for documentation and sharing. Map stays private to me, as it has many details and thoughts that aren’t necessarily useful for others.

I leverage tasks support a lot in such mind maps. They help me to track work progress and also make sure there are no forgotten nuances and risks.

Because mind maps are so easy to read, many times I was able to find forgotten or missed work for various projects. This helped me a lot, as otherwise we would either get a bug during testing or wouldn’t be able to launch on time. I believe, only text notes couldn’t have helped me in such cases.

However, I do not use mind maps for anything that requires lots of text. Documentation, design notes aren’t part of my interaction with MindNode. I also do not use mind maps for actual tasks and tracking work. There are better tools for these use cases. However, where mind maps are great at defining ideas for design, adding pros and cons, risks and vision; maps are also great for defining list of milestones and high level stories.

Summary

If you’ve never tried mind maps before, and also looking for a way to manage through your life and on work, then give a shot to mind maps.

MindNode is a tool that I’d recommend the most, assuming you are using macOS/iOS and ok to pay around $30.

Message Locker

Problem

Extreme requirements require interesting solutions. Sometimes there is a need to come up with hybrid solution, that not always seems to be beautiful on first sight. One example is a Message Locker solution.

In service oriented architecture, application consists of many services that interact with each other.

Inevitably comes a need to fight high latencies caused by remote calls and necessary serialization/deserialization ( in a huge chain of dependent services calls, where each call results in a network hop with required fees like data marshaling and passing data through the network, adds at least a few milliseconds extra for each call.)

Service that requires to gather output from multiple dependencies to do its job is an aggregating service.

Such service needs to be smart at how it calls dependencies. If they are called one by one, then their latencies would be accumulated. The most obvious way to prevent this is to call each dependency in parallel. Now, service own latency would be defined mostly by its slowest dependency. In this case, we say that slowest dependency is in the critical path.

Aggregating service isn’t complex because it needs to call multiple services in parallel. And usually, there is simple way to avoid creating another service, if only business value it adds is aggregating output of multiple dependencies.

But, aggregating service becomes complex when:
  1. It adds complex logic on top of the data returned by dependencies
  2. It has to be sophisticated at orchestrating calls to many dependencies.
The need to orchestrate comes from the nature of SOA: sometimes Service need to call one or more dependencies first to gather the data necessary to call another dependency. Often it’s not possible to call all dependencies in parallel and just aggregate replies once all are available. In many cases, Service needs to call dependency A, to get the data necessary to call dependency B, results from which are required to decide if Service needs to call dependency C or D and so on.

Optimal call of dependencies is often the most important thing to do when fighting high latencies. And thus, eventually comes a need to have Aggregating service, that can call multiple dependencies in a savvy way.

But, even when there is an aggregating service in use already, inevitably comes a need to fight high latencies. And there are only so many ways this can be done:
  1. decrease latency for each dependency in the critical path (often by pulling dependencies of own dependency, and call them first)
  2. call dependencies in even smarter way.

This post stops on the 2nd way. If aggregating service already parallelizes calls to dependencies as much as possible and there is no way to make it even better, then, to be honest, not much can be done anymore.

Seriously, when service A needs to call dependency B so it can call dependency C later, what else can be done to save extra 10 ms you need that much?

That’s where Message Locker comes useful. It goes to a bit nasty territory to allow save additional milliseconds in aggregating service.

Message Locker

"Message Locker" means a Locker for a Message. Service allows to store a message in the some kind of locker, so only specific client can grab it. If message is not received during certain period, message becomes unavailable.

Message Locker is a distributed service that stores all the data in the memory. Client that sends a message into the locker is called sender. Client that receives message from locker is called receiver.

Each message is stored in the locker using a unique random key. When sender puts a message into the locker, it also provides additional attributes, like:
  1. TTL - time to store the message in the locker,
  2. Reads - number of times the message can be received.

Message would be removed from the locker whenever received for defined number of times or once its TTL expired. These rules prevent Message Locker to be bloated with obsolete messages.

Even after message was removed, Message Locker is still aware of it previous presence. Whenever receiver tries to get evicted message, it gets an error immediately.

In case receiver tries to get a message that is not evicted yet, it is returned to the receiver, and number of reads is increased. This approach doesn’t handles retries properly though.

In case receiver tries to get a message that is not sent yet, then Message Locker will hold the request until message becomes available or timeout happens.

How to use Message Locker?

Given 3 services A, B and C. Service A is an aggregator service, that calls multiple other services, among them services B and C. Service B has to be called before service C, as its output is part of input for service C. Service A also uses output of service B for own needs later as well.

Normally, service A would call service B, wait for reply and then call service C. During this workflow, service A needs to do following work before it can call C. This extra work becomes part of critical path:
  1. wait for reply from service B
  2. read reply from service B
  3. construct and call service C.
Network and extra serialization/deserialization are often expensive operations, and when one works with large amounts of data, could take 5-10ms. In this case, construction request and making remote call to service C also can add additional 5-10ms.

Without Message Locker

This is where Message Locker becomes helpful. Workflow is now changed: service A calls service B with key K, and in parallel calls service A with key K, B puts its reply into MessageLocker using key K, service C receive this reply using key K. Service A also receives service B’s reply from Locker using key K, and does this in parallel with service C call.

With Message Locker

In this case, there are following notable changes:
  1. time to construct and call service C happens in parallel with call to service B, and as such is removed from critical path
  2. time to deserialize request and do necessary initial work by service C is also execute in parallel with call to service B, and as such is removed from critical path
  3. time to deserialize reply from service B in service A also happens in parallel with call to service C, and as such is removed from critical path
  4. time to call to Message Locker, receive and deserialize received data by service C are added to critical path. This would eliminate savings added by #2.

Using Message Locker also adds complexities:
  1. Service A, B and C need to be integrated with Message Locker
  2. Service A or B needs to know how many times message would be received from locker or what timeout to use in order to not overload Message Locker with not need message and not cause issues with message being removed to fast.

Why not use existing solutions like...

Message Locker by itself is very similar to well known existing solutions: Message Broker and Distributed Cache. Although similarities are strong, there are a few differences, that make Message Locker to stand out for its own very specific use case.

Message Broker?

Message Broker would usually have a predefined list of queues. Producers would send messages to the queue and Consumers would consume. It is possible to create temporary queue, but it is usually expensive operation. Message Broker usually assumes processing latencies are less important than other traits, like persistence or durability or transactionality.

In this case Message Broker can’t be a good replacement for Message Locker.

Distributed Cache?

Message Locker is more like a distributed cache, with additional limitations. Message is stored only for 1 or few reads or very limited amount of time. Message is removed from locker as soon as it becomes “received”.

In ordinary caching, it is expected that content becomes available for much longer period than it is in Message Locker.

Summary

Message Locker is a way to decrease latencies in aggregation services by enabling additional parallelization. This is possible, as dependency between services are organized through a proxy - Message Locker. It holds the replies from dependencies and provides them to the receiver as soon as they are available. This allows to further hide expensive operations: network call and serialization/deserialization.

This comes with additional complexities:
  1. Right value, for timeout and number of reads to evict, can be error prone to define,
  2. Message Locker development and support can be cumbersome as well,
  3. Restructuring services to benefit from Message Locker.

But when there is no other choice and latencies had to be increased, Message Locker could be a solution.

Ukrainian Tech Startups


I always return from my vacation in Ukraine with a few new books to read. There are many good book publishers nowadays, who provide a continuous stream of interesting books on Ukrainian language.

This time, among the books I’ve picked, there was one special. Not only it stood up on front of the others with an orange cover, but it also was about technological companies founded and now working in Ukraine.

Book name is “Стартап на мільйон. Як українці заробляють статки на технологіях”, which can be translated as “Startup for a million. How Ukrainians earn capital with technologies”.



Companies


It is about 14 Ukrainian companies that became successful based on technologies.
  • Depositophotos
  • Genesis
  • Na’vi
  • Grammarly
  • Macpaw
  • Prom.ua
  • Rozetka.ua
  • Jooble
  • Viewdle
  • Kodisoft
  • Приватбанк
  • Ecoisme
  • Petcube
  • Preply

Most of those companies are startups.

Findings


Before I started reading this book, I only knew 6 companies from this list, and had no idea that 2 of them are from Ukraine.

I decided to read the book during my flight back to Seattle. Soon I've realized that it was a right choice: such an interesting book to me that I’ve finished it by the moment I got to my destination. I always find flights a good place to read, but this time it was quite productive too. Lots of notes and highlights were left on the pages of the book and my notepad. Mostly related to 2 main topics: doing business in Ukraine and creating tech company.

Many years ago, I’ve heard that it is hard if even possible to create a successful IT business in Ukraine oriented on local market only: market is too small, local companies can’t offer competitive salary to software engineers or pay for software, and law is often too flexible to rely on it.
Companies described in the book prove this: with an exception of a couple companies, other’s have to work on external markets, which usually give a major income. Companies, like Genesis and Jooble, tried to create business oriented on local market, but that wasn’t enough for them. The only exception for this rule, is a couple of e-commerce companies: Rozetka.ua and Prom.ua (I don’t mention Приватбанк as it is a bank.)
Easy to make a conclusion that if you want to make a profitable start up oriented on Ukrainian market, it should be related to e-commerce. Not sure this conclusion is correct though.

Another finding is related to investments. Most of the companies accepted investments. Only few were financed by founders solely. Reason is obvious: not everyone had enough savings to invest into own company. Companies, who accepted external investments also received advices from investors on how to build a business.

There are 2 types of founders: serial entrepreneurs, who had already 1 or more companies behind their backs and professionals for whom that was a first company. Former benefited from existing connections, experience and capital. Later benefited from experience gained at previous work and also from investors suggestions.

Existing experience couldn’t be overestimated. Founders that had already created profitable business before, have higher chances to build a successful business.

Many companies are registered abroad (e.g. in USA) with a sister company in Ukraine, that does all the development. This helps to manage risks related to the IP and sometime unstable situation in Ukraine. HQ or development offices are mostly in Kyiv. Many founders emphasized numerous advantages of Kyiv among other capitals in Europe and world: good environment, low prices, lots of software engineers, reasonable salaries, close to EU etc.

There are always co-founders. Example with Rozetka.ua shows that wife could be a co-founder as well.

Connections are very important:
  • useful to know suppliers like it was with founder of Rozetka.ua
  • useful to have existing connections like it was with Grammarly
  • useful to have friends who could introduce you to useful people like with Genesis
  • useful to know the best around like it was with Na’vi

Each of those companies had a bad time at least once. Either there were no financing, or idea didn’t work or profits were too small etc. But all of them withstand raining days and are going to their next goal.

Lo and behold, companies with a focus on profit/success are the one that receive highest profits.

Highlights


I’ve made a lot of highlights, and want to share here only some of them:
  • “Вони зазделегідь підготувалися і перед звільненням відкладали гроші, щоб прожити якийсь час без зарплати. За словами Палієнка, на момент старту Prom.ua партнери мали досить заощаджень на рік-півтора економного життя.”
  • “Їсторії, коли людина стає успішною, виїхавши зі своєї культури вже дорослою, - вкрай рідкісні. Вони є, але в загальній масі статистично незначущі.”
  • “Я не дуже розумію людей, які звідси їдуть. Київ - одне з найкращих місць для життя.”
  • “Перші гроші Prom.ua заробив вже за кілька місяців після запуску - на рахунок компанії “впало” $5 завдяки реферальній програмі AdWords.”
  • “У той час їхній проект заробляв досить скромні $500 на місяць, але навіть такі доходи давали чималий привід для оптимізму… тільки на рекламу за перший рік було витрачено $15-20 тис.”
  • “Перший рік - це час дуже великої кількості експериментів, суть яких - адаптувати продукт під ринок. Головне - не впадати в зневіру й безупинно експериментувати, підганяючи продукт під ринок на базі тестувань, здорового глузду й того, що роблять конкуренти…”
  • “система аналізу даних може підказати, що замовити з певною стравою, і вивести список найпопулярніших справ у цьому закладі на основі відгуків інших клієнтів.”
  • “хребтом, на якому тримається тіло компанї, є стратегія.”
  • “Стартапери часто забувають, заради чого все почалося. Вони відхиляються від необхідної стратегії і, впираючися у перепони, звертають у той бік, куди їм простіше рухатися. При цьому обрана спочатку мета може опинитися не попереду, а за спиною.”
  • “Наступні два роки Чечоткін реінвестував до 90% прибутку в розвиток бізнесу.”

Conclusion


It is possible to create a tech startup Ukraine. However, at this moment you might need to focus largely on external markets. You also might benefit from registering company in US or EU.

Kyiv is a great place for HQ. Cities like Kyiv, Lviv, Kharkiv and Odesa are great places for development and R&D office.

First years would be the hardest, but founders should not lose focus and work hard to achieve success.

The most important SDE skill: Ownership

”Without ownership, there can be no leadership." - http://georgecouros.ca/blog/archives/3791

This post is about one of the most important leadership skills you can find: Ownership. I see it as a root of all other leadership skills. If you don't feel being an owner, you often don't feel neither responsibility, nor interest or empowerment to bring changes.


What is Ownership

Ownership is “the act, state, or right of possession something.” You can own computer, car or house. And as such, you feel an ownership to those things: you can install new software to you computer, clean it up, fight viruses, upgrade it etc. Same story is with car and house: you feel and are empowered to make changes and in your interest to make changes for better.

“Ownership is about getting something done no matter what. ” -http://www.tandemlaunch.com/ownership-versus-leadership/

There is also another definition of ownership. You take ownership when you feel responsibility for the results of your work: finishing up project, taking care of found issues, making future improvements. As an owner, I will get this project done, I will make sure it is tested and properly working, I will make sure that it delivers what my customers expects, and I will make sure that found issues will be resolved.


Ownership in Software Development

Actually, there is nothing special about being owner in software development. Development process is quite well defined: there are phases for gathering requirements, designing and planning, coding and testing, bug fixing and launching. List of artifacts is also well defined: source code, documentation, tests, metrics, list of issues and etc.


Group Ownership

Group ownership is also a shared ownership. Multiple software engineers own codebase, projects and features, specific modules or components. Usually, engineers in a team will have different level of ownership skills:

  • some would just do the work and won’t care much of the result,
  • some would focus on finishing single task successfully and wouldn’t care much of a whole picture
  • others would care mostly about their own feature/component and wouldn’t care of a whole projects
  • others go beyond and focus their attention on a whole project.

The higher ownership skills, the larger area they normally cover. I would call it an “ownership scale”.

Off topic: Ownership and Career Growth

Interesting that you can see a clear match between ownership scale and engineer’s position: junior software engineers are barely understand what is happening and focus on finishing up single task; mid-level engineers are focused on a codebase, features that they work on and, maybe, a few more aspects; senior engineers go beyond that and focus on a whole product or larger part of it.

Ownership level tells what are you focusing on as part of your everyday job and how how successfully you will be able to deliver results.

And based on this, I make a statement that Ownership skill should be an important part of promotion evaluation, same as technical skills are.

Working in a team is always harder than working on your own. Dealing with more people that are owners of the product (just like you) is even harder.

Group ownership requires to take into consideration thoughts and ideas of other owners. There is no a simple way to make a decision now. But luckily you get more than just a headache. Discussion with other owners can help find both consensus and a better way. It is because all owners are focused on improving things and successful delivery, not on own ego satisfaction.

The strategy of “my ownership is better than your ownership” is a lose-lose strategy. Such behavior will kill or suppress ownership attitude in others. As an owner who care about the product, searching for a path to success, you lose like minded people who could help you here. Demotivated ownership might even cause an opposite to ownership behavior. Real owner would grow other owners around, b/c in a team work this is the most effective way to delivery successful product.


Examples

Here I’m going to provide a list of different behaviors and try to give my opinion on ownership level.

  • Mark finally finished the project he didn’t like much. And now he is not eager to work on the related bug that was found recently. I think you would agree with me, if I would say that Mark’s ownership level is not very high. First of all, Mark didn’t like the project and now attempts to skip working on issues that are result of his previous work.
  • Hanna finished working on the project that she was assigned. She didn’t want to work on this project, but business really wanted it. But Hanna took the project and work it through and delivered successfully. Now business loves Hanna and has a new project for her. This is a good example of ownership. Hanna took the project she didn’t want at first, but liked eventually and could deliver it successfully.
  • John was asked to help with task for project X. John was really helpful and could finish task successfully. He also fixed a few issues he had found, and helped Sarah to develop analytics module faster. Project X was released on time with John’s help. This is a great example of ownership. John was just asked to help with a task. Instead, he take a responsibility to fix issues and help Sarah with her work on the project. Don’t be like Mark, be like John.
  • Lisa works only on the tasks that she was assigned. She doesn’t spend much time learning to do her work better. Lisa also doesn’t spend time to see how she could improve the project. Most of the time she spends on tasks added by others. Whenever she finishes with task, she moves next without a necessary testing. I’m not sure that I see any ownership here. Lisa is not owner: she doesn’t care about results and quality of her work.

Summary

In todays world, having a great technical skills is only one important part that makes a successful software engineer. But there is more than it. Ownership skill is another important part. It is important for engineer to get projects done successfully, improve team, processes and software.

If, after so many years improving technically, you still find you need to get better, then switch your focus to improving your Ownership skills.

Iterate Quickly

That's what others recommend

Recently I've being reading 2 different texts, and they both mentioned how high-velocity iterations are important and better than high-quality iterations.

First one, is article by Jeff Atwood, where author writes about “Boyd’s Law of Iteration”. Article is quite interesting. It introduces us into the history behind the Boyd's law of iteration. Article as well emphasizes the law itself: speed of iteration beats quality of iteration.

Second one, is latest annual later by Jeff Bezos to shareholders. In section "High-Velocity Decision Making", author also emphasizes superiority of high-velocity decisions over high-quality decisions. Interesting that Jeff Bezos finds that 70% of useful information is usually enough to make a decision. Waiting for another 20% or 30% of data might take too much time, and might be not as much beneficial.

In both cases, authors notice that making quick decisions and iterating fast can only work well if there is enough information available originally. And feedback is used to correct the course continuously during quick iterations.

In book The 5 Elements of Effective Thinking, authors also emphasize the importance to start fast. In section dedicated to making mistakes, authors encourage to not be afraid to start with mistake (if you don't know where to start), but continuously iterate incorporating received feedback and new knowledge.

Iterate Quickly in Software Development

What does it mean to iterate quickly in software development. I'm going to throw a few ideas, even though they are quite obvious:
  1. Plan smaller and deliverables for each milestone:
    • define list of milestones
    • know deliverables for each milestone
    • plan time to receive and incorporate received feedback
    • follow the feedback, not the original plan: course-correcting is the right way to go.
  2. Start testing faster:
    • write unit tests
    • write functional and integration tests
    • use staging for deploying latest versions
  3. Deliver features faster:
    • if can't deliver a complete feature, then deliver part of it
    • if can't deliver to all customers, then deliver to some only, like internal or beta users
  4. Sprint should take less time:
    • 1 month sprint is too slow in most cases
    • don't forget to make sprint retrospectives
  5. Collect feedback from users continuously.

Why I am Not Sure that TDD is the Only Right Thing

Let's say you have a project to deliver feature XYZ. After analysis, design and planning, you came up with a term of 2 months: 2 weeks for scoping a work, 4 weeks for coding and 2 weeks for testing. Sounds great.

As anything else, testing has multiple perspectives. The most obvious one is verifying results of your work and keeping quality under control. The other one, less obvious, is minimizing the risks caused by numerous bugs. Third one is related to previous two: minimizing the cost of software development and support. The earlier you test, the easier it is to fix and less bugs you have later.

Lets look at two possible scenarios:

Scenario 1: No unit tests

So you don't believe in unit tests or you just don't have a time to write them. You'll better test everything manually during 2 weeks of test phase.

You have finished with your code, and now it is time to wire everything up and start testing. Oops. You found a small bug, where you just had forgotten to add "!" in your if statement. Quick fix. Easy peasy. You make a change. Your favorite build tool picks your last commit and makes a new build. After 10 minutes you have a binary. Another 5-10 minutes and you have it deployed and ready for testing.

You test it again, and... Oops. You found a small bug. Looks like you actually need to call that method first, otherwise you get NPE. Damn. What a stupid mistake?! Quick fix. Easy peasy. You make a change. Your favorite build tool picks you last commit and makes a new build. After 10 minutes you have a binary.

You test it again, and... Oops. You found a small bug. Well, I guess you see where I'm heading. 2 small stupid bugs, you already spent 1 hour. You have only 2 weeks, but you can’t even get it working for happy case, don’t mention for all other dozens of test cases.

And nothing prevents you from regressions during bug fixing.

You probably see now, what is wrong with this scenario. You think you've saved time during coding, but actually you didn't.

Scenario1

Unit tests are a convenient way to spread testing work throughout development phase. So you'd need to do less during testing phase, where fixing bug is already an expensive thing.

I rarely find bugs when I write unit tests. Maybe 1 in 20 tests that I had actually found and fixed a bug. But, man, this is so fast to fix a problem at this time. Everything is locally on my machine in my IDE. I don’t need to build and deploy change, neither others are blocked by me. Found, fixed, done! A tad of time here, saves hours later!

Scenario 2: Write unit tests during coding

So by now you've decided to try out writing unit tests. Maybe this will help to avoid the hell you've had during Scenario 1. You start writing unit tests for most of the code you produce. It has been really hard at first, but later became easier. You use mocking a lot and thus unit testing becomes almost painless. Actually, you can't imagine now how to write new code without tests, but time to time you skip writing tests for less important parts.

You've finished you coding by now, and ready to start testing. And you find that there are not that much bugs now. And when you find a bug, you know how quickly to fix it and verify with unit tests. Thus, you don't need to go through tedious fix-build-deploy-verify cycle as you used to do during Scenario 1.

Scenario2

As result, you spend more time during coding phase, as you need to write unit tests. You however spend less time during testing phase, as you can iterate bug-fixing faster.

Of course, you still spend a tad more time than planned: but it is because you need to learn how to estimate better!

EstimationSkills

TDD vs Plan Ahead

Assume we have 3 approaches:
  1. you follow TDD and write tests first, and then write code to make your tests pass eventually
  2. you take a paper or text file, and you plan ahead by writing a list of test cases that need to be converted to automated test suites; then you code and write test cases during coding or afterwards
  3. you don't plan what test cases you have, you just write a code and cover it sporadically with unit tests
It is probably clear that 3rd approach is the lacking one here. You start writing code without defining what are your expectations. You don't have a plan of what needs to be tested. As result, it is easy to miss many important test cases.

1st and 2nd approaches sound very similar, as they both have the same goal: know and plan what you're going to do before you start coding.

However, 1st approach forces you to build constraints for you and your code before you start coding. Of course, you can refactor those later, again and again. While 2nd approach gives you a flexibility to write the code and refactor it until it fits your vision. You can now create tests during or after you've finished with piece of code.

Both 1st and 2nd approach require self-discipline, but in different ways. TDD needs a discipline to start and keep to using it. 2nd approach needs a discipline to convert test cases on paper to unit tests in code.

Not obvious difference between 1st and 2nd approaches is completeness: it is easy to miss something when you write a code. If you start defining a list of test cases on paper, it is always easier to identify completed list.

Summary

Here are some bullet points as a summary from this post:
  • writing unit and functional tests is important to keep quality under control, save time and money
  • it is never too late to write tests for the code, but now is better than later
  • thus, write tests during coding and before commit and code review
  • writing tests before code does not make things cheaper or better, unless you don't have a discipline to cover functionality with tests
  • we need to work on improving our estimation skills.

Structured Aggregated Log

Introduction

Structured logging is an approach to logging where information is written in a structured form, that later could be read and parsed by machine with minimum efforts. In many cases, it means that immediate readability of the log is reduced, but with a bit of efforts it could have an opposite effect (we’ll see it a bit later).

Such different Structured Logging

This structure can be anything: from comma separate list of values to complex JSON/XML documents.

Structured logging’s another important difference is focusing on logging larger number of information in batches.

For example, you have an application that reads data and passes those through a chain of rules. Each rule can either vote to execute some specific action over those data later or not.

There are a few approached to logging data here. Lets review them.

Unstructured log line. Each class writes a log line with information it currently contains. There is no common structure for log printed by each rule. Thus easy to notice a different ways of saying the same. In logs below, one rule says ‘Voting for action’ while another says ‘action is picked’. Some rules print important information and others don’t. Such logs can be parsed by human but not always by computer.

Structured log line. This is better. At least same approach is used for logging all information. Yes, it is not always easy to read by human, but it is in a state where both human and computer can read and interpret those logs.

Structured aggregated log line. Simple here: you gather all the “execution” data and then output them at the end in a single structured log line. In this case it is preferable to use JSON or XML to structure the information. CSV most probably won’t be the best option here, especially because it doesn’t support nested structures. Pros: you have a single line with all data. Cons: you need to keep those data until final log line is generated and also it is hard to read those without practice or a formatting tool.

Which one is my favorite? – The last one!

Why? – Because it can hold important information in a single line and save me from grepping and parsing multiple log lines.

Structured Aggregated Log Line

For structure aggregated log, there is a little help from most of logging frameworks. So this functionality needs to be built manually.

Main components of structured aggregated log are aggregated log collector, data formatter and logging framework to output.

AggregatedLogDataComponents.png

Lets get deeply into pros and cons of structured aggregated log line.

First start with good things:

  1. You have all information aggregated into single log line
  2. When using JSON or XML, you could benefit from auto-formatting tools
  3. Even better for program to parse and read data from such log line
  4. Better control on output data:
    1. Customize output strategies
    2. De-duplicate data (printing same thing once)
    3. Structure data in usable way that simplifies understanding
  5. De-duplicating log metadata: skip printing duplicate date/time, level and source of logs etc.

There are of course bad things:

  1. Probably is not supported by “your favorite” logging library. So need to be implemented manually
  2. Need to store aggregated data, and also building a JSON/XML document to print
  3. Average log lines become huge and hard to parse by human (however auto-formatting tools help a lot)
  4. Logger should support printing partially populated aggregated data (more on this below.)

I’m going to deep dive into some items mentioned above to explain in details and, if possible, with examples.

Auto-formatting

This is simple. You found a log line, copied it into auto-formatting tool, pressed the button and you have a well formatted and easier to understand log:

formatted_structured_log.png

Customized output strategies

This one is quite important. As you have aggregated data and you need to generate your log line, it becomes similar to how you generate a “view” based on “model” in MVC pattern.

You can do many useful things now:

  • generate JSON log line, or XML
  • generate short log line with the most important information for successful use
  • or generate a long log line full of all aggregated data in case error or exception happened
  • filter out unimportant and don’t print them into output log
  • etc.

De-duplicating data

Lets compare examples of unstructured/structured log lines:

They both have a date/time and log level and request id for every log line. We get rid of this duplicate data if we print all data in single line.

But that’s not all. In both use cases, TrafficLightIsGreenRule and TrafficLightIsRedRule print traffic light status. Those are independent rules, and traffic light is important for both of them so they both print it. However, in structured aggregated log line, we print traffic light status only once.

Handling errors

Errors happen. So might happen one before you’ve aggregated all the data and printed them into log. How to deal with this? The most important here is to not lose data aggregated for logging: those need to be printed in any case even though they aren’t complete. Those would be invaluable source of information during error investigation.

Often it is possible and recommendable to print exhaustive data into an aggregated log.

Or alternative would be to collect error message and stack trace into the aggregated log data:

Presentation

As mentioned before, one of the strong benefits of structured aggregated log line is presence of important data in a single line. And this line is in the format that easily understood by machine.

This allows to read data out from the log and do various manipulations. Like generating a better way to present and work with data.

I tried to imagine a way I could get a JSON log line, parse out data from it and convert into readable HTML document, that gives me a better view of data. For sure, this is not very helpful with mine trivial example. But for a larger logs this is more beneficial.


HtmlPresentation.png

Creating a simple tool where you can paste a log line and get such presentation of data wouldn’t be a big task. But would help to decrease a level of operational load.

Jenkins Pipeline

Introduction


I believe in simplicity. It means I think things should be simple to work with.
It doesn't mean that it always should be simple inside. It could be complex, sometimes very complex.

At the same time, I distinguish two types of complexity:
  1. complexity caused by indirect and non-obvious relationships between components,
  2. complexity caused by mess within components itself and messy relationships between them
First one means product could be implemented in a very smart way, built on large number of implicit assumptions, often non-obvious.

Second one means product's complexity is exaggerated by very confusing, illogical and messed up relationships between components. Unlike the first one, relationships exists, but they make no sense not because they are so over-smartly designed, but because they are spaghetti-like.

Often those two types could be met together in same product. Hope you'd never had a chance to deal with such.

The way to fix complexity type #1 is to remove implicit assumptions by adding smaller components with visible relationships.

However, to fix complexity type #2, you need to understand it deeply. What if thing is complicated b/c you can't understand it yet at this moment? To be able to answer this question, I always start with research. And my research has some kind of diagram. I believe that visualization is the best way to tackle complexity. At least it always works well for me.

Simply put, visualization is one of the best ways to simplify hard and complex things. Even if this is a very basic diagram, it is still better than nothing. Sometimes, it requires a time to find a correct form of visualization within correct level of abstraction, but once you did it, you are half done.

Continuous Deployment


And this post is about visualization; and how it can help to combine parts into a single simple picture. And more specifically, it is about how visualization can help simplifying continuous delivery.

Continuous delivery is a process of getting you product from source code and into production. It usually happens through a pipeline of jobs: first job is compiling source code and building artifacts, then goes integration testing , deploying to staging environment, and eventually to production. For example, in Jenkins job is usually created for each of these steps, where each job triggers next one once it's finished successfully. Fore example, there would be jobs like 'Build XYZ,' 'Test XYZ,' 'Deploy XYZ to Staging,' 'Deploy XYZ to 1-box' and 'Deploy XYZ to Production'.

Default Jenkins View would present those jobs as a list, with no visible relationships between those. But there are relationships between them. And actually all those jobs are here for the single most important goal: get new version into production for the customers! So relationships play important role, which is hidden from us as users.

You might not even feel it immediately, but this presentation of jobs list brings a complexity. There is a sense behind those jobs, but it is normally hidden from viewer, unless one ready to spend time to understand how things work.

Pipelines in Jenkins


But good thing is Jenkins already allows you to remove this complexity. And it's via visualization of the pipeline of jobs you've created.

This support is brought by "Build Pipeline Plugin". This plugin adds a new "View" type called "Build Pipeline View".



In a next step you would need to pick your first job in the pipeline.



Then pipeline would be created based on jobs dependencies: this pipeline will contain jobs that would be triggered by first job, and also jobs which are triggered by that jobs and so on.

And now once someone makes a change into XYZ source, a new job for "Build XYZ" would be triggered. Once this job is finished successfully, it will trigger "Text XYZ" and so on. As you see no functionality change happened here, but with pipelines it is possible to visualize both dependencies between those jobs and what is a current state of the CD process.



That makes things so simple to work with. You can understand build structure and current state with a single glance.

More to that, Jenkins 2.0 comes with built it support for pipelines.

Blue Ocean


I'd also like to mention the initiative called "Blue Ocean" which sets a goal to build a better visualization of pipelines in Jenkins. I'd be happy to see it in live one day.

Other Products


There are bunch of other products that would help you to create build / deployment pipeline:
  1. AWS CodePipeline - https://aws.amazon.com/codepipeline/
  2. Concoure CI - https://concourse.ci/
  3. Bitbucket Pipelines - https://bitbucket.org/product/features/pipelines