bookmark_borderAnonymous code reviews

In the dynamic world of software development, code reviews are a staple practice aimed at improving code quality, sharing knowledge, and ensuring consistency across the codebase. However, while the intentions behind code reviews are positive, the process can sometimes lead to unintended negative consequences.

Receiving critical feedback on one’s work can be tough. Even when feedback is constructive, it can sometimes be perceived as a personal attack, leading to hurt feelings and reduced morale among developers.

Code reviews can be used as a tool to leverage power over colleagues. Meticulous reviews with excessive back-and-forth comments can significantly slow down a developer’s productivity. This not only impacts individual performance but can also affect team dynamics and project timelines.

Biases, whether conscious or unconscious, can influence code reviews. Some reviewers might be harsher on certain individuals or more lenient on others, leading to discriminatory practices disguised as professional feedback. Conversely, pull requests from favored individuals might be accepted with minimal scrutiny, compromising code quality. All in all it can be discrimination under the cloak of professionalism.

Given these potential pitfalls, it’s clear that the traditional code review process has its flaws. To mitigate these issues, we should consider anonymizing code reviews.

Why We Should Consider Anonymizing Code Reviews

  1. Protecting Feelings and Morale: By anonymizing the process, feedback is perceived as purely objective, focusing solely on the code rather than the individual. This helps in reducing personal biases and ensures that criticism is seen as constructive, not personal.
  2. Preventing Discriminatory Practices: Anonymity removes personal identifiers, thereby minimizing biases based on race, gender, seniority, or any other personal attribute. This promotes a fairer and more inclusive review process.
  3. Ensuring Objectivity and Fairness: When reviewers and authors remain anonymous, the emphasis is on the quality of the code. This fosters a more objective and balanced assessment, leading to better code quality and a healthier team environment.
  4. Mitigating Productivity Hits: An anonymous system discourages the misuse of code reviews to deliberately slow down a colleague’s progress. The focus remains on providing genuine, constructive feedback, thereby maintaining productivity and ensuring timely project completions.
  5. Leveraging LLMs for Neutral Language: Utilizing Language Models (LLMs) to standardize the language in comments can further ensure anonymity. This prevents reviewers from guessing identities based on writing style, fostering an environment where feedback is purely based on the code.
  6. Equality in Approval: Anonymity ensures that code is approved based on merit, not personal relationships. This builds a culture of fairness and meritocracy, where every developer has an equal opportunity to contribute and grow.

Adopting anonymous code reviews can transform our workflows, making them more equitable and focused purely on improving code quality. It’s time to embrace this change for a healthier, more productive development environment.

bookmark_borderWorking code isn’t enough

In a great book “A philosophy of software design” John Ousterhout points out that software engineering is not only about quick delivery of digital products. He stresses the importance of long-term perspective – strategic programming. This idea is well known at least since Clean Code, but still somehow ignored. For some reason, many view refactoring or improving code structure as merely a fanciful dream of coders chasing perfection.

It’s the opposite. It’s a necessity if we don’t want the project to collapse.

“The most important thing is the long-term structure of the system. (…) Your primary goal must be to produce a great design, which also happens to work” – says Ousterhout.

It doesn’t mean we should chase beauty and not deliver. It means we must remember that delivering poorly structured code will soon – much sooner than most of us think – cause issues.

POCs become MVPs, MVPs become products, products start earning money, they need scaling, and new features… and boom – suddenly company needs 5 developers to slowly implement new functionalities and perform basic maintenance of an application which was written by one intern in two months.

The inception of a project should always be the most appreciated and well-planned stage. Like pregnancy. We don’t drink, smoke and party in the 1st trimester just to eat whole foods in 8th month – but it’s exactly what we do with code of our IT projects often. We do whatever in the first stage, and then when it’s too late we bring the best engineers to save it.

Remember, engineers: strive to create the best designs possible. Our lives depend on it!

bookmark_borderEnglish names of programming special characters

Many developers are not native English speakers. Some special characters used in programming may be difficult to remember. Here is a list of special characters used in programming with their names in English:

{, }Braces, curly brackets
{Left brace
}Right brace
(, )Parentheses, round brackets
(Open / left bracket / parenthesis
)Close / right bracket / parenthesis
[, ]Square brackets, brackets
[Open / left bracket
]Close /right bracket
!Exclamation mark
@ampersand
*asterisk
Hyphen, dash
_underscore
=Equal sign
:colon
;semicolon
,comma
.Period, dot
Less than, angle brackets
Greater than, angle brackets
/Forward slash
\Backslash
~Tilde
`Grave accent, backtick, back quote

bookmark_borderThe most useful docker commands

List of containers: docker ps

List of images: docker image ls

Build container from dockerfile in current directory: docker build -t [container name] .

Run container in the background: docker run -d -p [container port] : [host port] [container name]

Get logs from container: docker logs [container hash]

Login to container: docker exec -it [container hash] bash

bookmark_borderHow to reject all changes in Git?

If you want to reject all changes in your local git repository you must:

  1. Discard local changes
  2. Remove untracked files

To discard all local changes run:

git reset --hard

To remove untracked files run:

git clean -df

After executing these two commands you will have no changes whatsoever. If you run git status you should receive:

“nothing to commit, working tree clean”

bookmark_borderWhat is technical debt?

A picture is worth a thousand words. Technical debt is what you see above. A temporary solution that over a period became a problem. Sometimes smaller, sometimes bigger. But the longer we wait the bigger is the risk it will explode and cover our business with odorous excrement. Moreover, like any debt, the longer we keep the liability, the bigger our payback will be.

You could say – who would be so careless to keep such a temporary solution for a long time! You are right. But as they say, temporary workarounds are the most persistent ones. Sometimes there is no time. Sometimes there are no resources. Later there is no time or resources to transform a temporary solution into something proper. Therefore, it stays with us. Until it becomes dangerous.

Technical debt exists in every IT project. In other forms, this phenomenon exists everywhere. In our home, at some messy place which starts to grow until suddenly we realize our whole apartment is a mess. In our body, where few cells grow out of control, and after many years we are diagnosed with cancer. In any business, where crucial operations are done by some single old person who suddenly dies or uses some ancient hardware that breaks and destroys the whole company.

Technical debt is a seed of chaos. The responsibility of software developers and IT managers is to keep it under control. Otherwise, we will be consumed by it one day. No matter the cost – let’s do not let it grow!

bookmark_borderHey Google, could you please add a .gitignore-like option to Google Drive?

Google products are awesome. Gmail, Android, and Google search engine itself. Whoever used Duckduckgo or Baidu knows how awesome Google search engine is… There’s however one thing which drives me crazy: it’s Google Drive.

In particular, the sync engine of Google Drive app. It’s far from perfect, but the worst thing is when you, as a developer, accidentally leave some node_modules inside the synced directory. Then the whole thing literally explodes. As all of the devs know node_modules directory is the heaviest object in the universe…

When Google Drive tries to sync it we can go and grab a coffee. We can grab it from the plant in South America by swimming in a canoe through the ocean, wait until it grows, pick it, bring it to the USA or Europe or wherever we live, wash the beans, burn them, design our custom coffee machine, make a coffee, and then if we’re lucky we can go back to our computer and see the sync finished.

I tried to find a solution. I found this crazy discussion for example https://superuser.com/questions/820145/google-drive-with-a-gitignore-like-option. Poor admins build some custom scripts to make symlinks to the directories which they want to exclude from syncing. Or they remove the directories before running the syncing engine.

Therefore I’d like to pray to Google itself. Please, I beg you, oh mighty – add the exclusion mechanism to the Google Drive sync app so we can exclude the directories, files, anything, just like we can simply do it with .gitignore file. I know you’re busy, I know it might take a long time, but please. It will make the world a bit better place to live. Thanks in advance, Google 🙂

bookmark_borderWhat does question mark and dot operator ?. mean in C# 6.0?

C# 6.0 introduced new operator – null conditional operator ?.

The way it works is very simple. It checks if the left part of the expression is null and if it’s not it returns the right part. Otherwise, it returns null.

Simple example:

var thisWillBeNulll = someObject.NullProperty?.NestedProperty;
var thisWilllBeNestedProperty = someObject.NotNullProperty?.NestedProperty;

Executable example:

//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Rextester
{
    public class Person
    {
        public string Name { get; set; }
    }
	
    public class Dog 
    {
        public Person Owner { get; set; }
    } 
    
    public class Program
    {
        public static void Main(string[] args)
        {
            Dog dog = new Dog();
            Console.WriteLine(dog.Owner?.Name == null);
            // this will print True
            dog.Owner = new Person() { Name = "Fred" };
            Console.WriteLine(dog.Owner?.Name); 
            // this will print Fred
        }
    }
}

The above example can be executed here: https://rextester.com/TBC19437

Documentation: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators–and-

bookmark_borderDRY is dead

The DRY principle, together with YAGNI, SOLID or KISS, is one of the most popular acronyms which shaped our way of thinking about developing software. It is simple, intuitive and easy to learn even during the early stages of education. However, the principle has been born in completely different circumstances than what we are dealing with today.

Simple idea

I’m not a historian of the software development and I’m not sure how the DRY principle has been born, but I guess it was created during procedural programming age. It stinks with a procedural way of thinking anyway.

The idea is simple. We have some code. The code should be organized. As long as we have some part of the code which repeats here and there we should create a procedure – extract this block of code, give it a name and reuse it.

Time flows

Since procedural programming things have changed. First of all the object-oriented paradigm explosion has happened. The complexity of the software has been growing. The systems for accounting, summing long rows of numbers, generating reports have been already created. The new frontier was internet browsers, instant messaging apps, trading systems for companies and snake for Nokia 3310. Except for the last one – it was quite a challenge.

The DRY principle doesn’t fit OOP as much as the procedural paradigm. Actually, if you think about it – it doesn’t fit at all.

Let’s think for a while – what happens when we try to avoid repetition in object-oriented code? First what comes to our mind is probably inheritance – the beautiful useless idea. The dog has a name, the cat has a name so let’s create a class Animal with property Name. But wait a second. Wild animals don’t have names. Let’s create WildAnimal and DomesticAnimal. Damn! – almost nobody gives names to fish…

Second popular solution for repetition problem is utils or commons.

There’s a secret rule in the software industry – every complex enough project has utils directory or class. Some of them 8k, 16k LoC.

It’s avoidable, it’s possible to properly design object-oriented software without these cancer cells of utils and disastrous inheritance. Please keep in mind anyway that both of them are the result of the DRY principle application. We tried, in the most easy, cheap way, to not repeat ourselves.

Microservices – nail in the coffin

Once upon a time I asked a colleague who worked at Amazon – the company which is a role model, a pioneer of microservice architecture – how do they organize common parts of the project, how they manage reusability, he answered:

We don’t. We do repeat. It’s cheaper and quicker at that scale of the project. 

The enormous size of the systems we are developing nowadays entails a new approach and different rules. The most visible tendency recently is breaking down problems and systems into smaller ones. Actually it is one of the main techniques since the beginning of software development, but recently it becomes more important than ever before. We can spot this trend in front-end frameworks (Angular, React – componentization), as well as in back-end (microservices architecture).

To some extent, we can think of it as a proper way of object orientation, more proper than inheritance. The organisms are similar but not the same. They do not, strictly speaking, share some features. The human eye is not the same as a dog’s or hawk’s eye. Only seemingly, on the level of naming these objects, they’re the same. Implementation details differ greatly. I’m not a genetic scientist but I bet that if we cut out from human DNA the parts which we don’t share with monkeys it will not create a monkey. I guess there are many subtle differences, some small parts of genetic code, few “lines” which make a difference even if most of the code is the same.

What to do?

It seems that the DRY principle became harmful. Should we stop using it? Maybe. For sure we should use it more carefully. In many scenarios, it may bring more harm than good. In some cases repeated code can be signature of failure, in some cases, it may be the best possible solution.

Is it bad when we repeat the identical code twice? If we repeat within the same class – I guess it is; in the same module – maybe; if it’s repeated in the same project, which consists of 100k LoC, and repetition happened in different modules – maybe not.

Is partial code repetition bad? Well, maybe it’s not bad by default, but it depends. Depends on the possibility to create a proper abstraction to avoid it. Quite often we use principles very strictly. Don’t. Don’t follow these rules blindly because they’re merely suggestions.

bookmark_borderWhat happens when the scrum team gets too big?

Participating in an overgrown scrum team is a fascinating experience. It allows us to observe how the framework collapses under its own weight.

Basically, scrum consists of meetings. Daily stand-ups, backlog refinements, sprint planning, review, and retrospective. These meetings, in theory, can consume even 22.5% of developers’ time. That’s a lot. But as always – it depends.

Image result for office sleep

Observation 1 – meetings get longer

Let’s start with a daily scrum. It should last no longer than 15 minutes. As long as the team is just a few developers big – it’s easy. But when we have 15 devs we can give everyone only one minute to speak. It’s pretty impossible. Either we will destroy the idea of the daily meeting – where the team members can properly describe what they worked on and ask for help (by forcing them to speak extremely short) either we’ll extend the time. In the team of 14 developers, I’ve seen daily scrum to grow up to 25 minutes.

Exactly the same is the situation with every other meeting. But in case of refinements or sprint review, it’s getting even worse because these meetings are naturally longer than daily scrum.

Observation 2 – meetings become full of things you don’t need to hear

As the team grows, the scope of work grows. Naturally – as in any big enough group – the subgroups form up. It can be any kind of division – front-end and back-end devs; people who work on feature A, and another group working on feature B; Java, and JavaScript programmers. When they work on the everyday tasks they almost don’t talk to each other unless they need to discuss some API or contract which is necessary for the parts of the system to communicate. But if the scrum team doesn’t split they’re forced to participate in the meetings together.

Then you find yourself in a meeting where half of the time is spent on discussing the things you don’t need to hear. You’re let’s say a JavaScript developer and last 30 minutes of a meeting was a discussion about back-end, or you’re developing database structure while implementation of the UI of the system is estimated.

Observation 3 – productivity plummets

You want to code. That’s why you became a software engineer. You like to focus, you love to create lines of instructions. This is also why, all in all, you’re getting paid. You automate processes, therefore, people don’t need to be employed to make them manually and the company is more effective. The money saved on automation goes to your pocket. Everybody is happy.

Unless you can’t code.

When the length of scrum meetings get longer it consumes your coding time. When the meetings get boring it consumes your mental energy. You become less productive. Not cool.

That’s why Scrum guide recommends a scrum team to be between 3 and 9 developers. Even if it seems difficult to divide – it’s necessary. The alternative is a small crowd of unhappy, ineffective developers.