5 habits when you should revisit your skills

Michael Spitsin
6 min readJan 31, 2022

--

Unless you just don’t want to work for money

1. You always rewrite the project from the scratch after receiving it from the other team

How many times have I read about new architectures or other success team stories in a next way: «We took the project. It was horrible and clumsy. We decided to rewrite everything. And now we have an ideal app that solves all our problems».

While it’s totally okay that the project can look completely different after the years of development, I think that it should be done gradually, line by line, method by method. Not just stop the actual work and rewrite everything.

Still, there can be exceptions, when it is really gainful to rework the project from the scratch instead of just adjusting it incrementally, yes. But those situations should be exceptional, not common.

Typically what I saw, were the projects with clumsy code, lack of docs or comments explaining why different approaches were chosen; absence of code consistency; no tests; redundant architecture layers; too many verbosity solutions.

All of that can be divided into small steps and refactored bit by bit, without stopping the whole process of features development. I already wrote about that in one of my previous posts.

Still, there are teams (and in big companies) too, who practice that. And while there are exceptions, I think you should think twice or even trice before making such decision.

2. You always start searching a library, when you need to solve some problem

«Everything is done before us» that’s totally correct. But at the same time, nothing is solving only our particular problem. Most of the «big» libraries we are using are aimed to be adjustable and changeable, so you can tool it for your particular case.

While there are cases when we are using some «default» not reglemented set of libraries in the new project, we should stop and think every time we try to search for a solution.

Can write the solution yourself? It can be really simple but instead you already trying to put +1 library inside the project.

Or if you will use the library, will it be flexible enough to fit your needs in the future? Is it easier to dig inside a big complex library with lots of settings instead of writing your own solution, which covers only 10% of its functionality but will be sharpened for your concrete job?

Besides, there are some cases when the library is really small, like one or two classes. Is it really worth putting it inside your project and +1 to its complexity, or you can just spend time to adjust this couple of entities, so it will be more integrated with your system, and thus potentially will be more consistent with a codebase?

I also wrote about such problem in one of my previous articles.

You trying to apply your habit patterns everywhere instead of tackling problems individually

Example 1:

Let’s admit, we all have our set of «default» libraries that we like to use. Yes, that set grows as time passes. And yes, we get used to it. Now you walking around all so confident about your libraries. You using Retrofit, you always used it, right? And… next thing you need to do is the app with JSON-RPC queries.

You don’t have much time for digging and handling that. So you decide to use Retrofit with it. The library is aimed to be used with REST, but «sure, why not use it with RPC». What can possibly go wrong?

And then you face the situation that all your methods in the interface are marked with @POST annotation and point to the root path:

@POST(«/»)
fun oneRpcMethod(args)

@POST(«/»)
fun secondRpcMethod(args)

You already have some dirt in your code. Why? Because you didn’t want to spend some time, thinking about other approaches. And that is only the surface. You will also need to handle args since jRPC is a strict protocol. You will also need to think about batching queries into one because it will save some time and network usage. And RPC allows that.

Some time ago we faced that problem and with this clumsy solution. Back then we didn’t find any library that could work with RPC in such an intelligent way as Retrofit works with REST. And we made our own internal library. It was discussed and weighted decision, but I’m not saying that you need to do the same. You can think about providing your own proxy, that wraps Retrofit’s work with your own annotations to reduce the boilerplate, for instance. It will take much less time, but you will drastically improve your solution already.

Example 2:

Another more general example is when you read about Clean Architecture, about all those layers. You listened Uncle’s Bob pretty old presentation. You even read his book. But you missed a tiny little idea that all those layers are not necessary and should be provided when they are really needed because each layer increases the complexity and thus maintainability.

I’ve been in one project when there was the next situation:

view.setOnClickListener { presenter.onSaveClick() }

//presenter:
fun onSaveClick() = interactor.save(data)

//interactor
fun save(data: Data) = repository.save(data)

//repository
fun save(data: Data) = api.save(data)

Why does the implementor of that feature need the interactor and repository, if they only delegate work? He explained it something like that “because it will be the same as the rest of the code“. No. I can not agree with that. We invent all those Daggers/Retrofits/Kotlins to reduce the boilerplate of our code and at the same time produce it with our misbelieved solutions.

Habits are a good thing to optimize our work. But they start to make harm when you apply them to every project, every team, every company. Recently I joined a new company, and now I’m even not sure about using basic principles everywhere, because the code base is HUGE and it is hard to make everything not repeatable or use the same code approaches everywhere 🤷‍♂️

4. You think that’s comments are redundant and code should be self-readable

Yeah-yeah, I know, that there is a book “Clean Code” by our famous Uncle Bob. And it is written there:

Keep in mind, however, that the only truly good comment is the comment you found a way not to write.

But admit it (if you saw a lot of projects and a lot of code) there were situations when you see a pretty readable chunk of code, and still don’t have 100% confidence, in what’s going on globally.

Here I think I should stop and explicitly say, that here I’m mixing up comments and docs into one entity, whereas in the reality I’m sure, nobody is against a good class/method doc, but the question is about comments of some lines.

Yes, some comments are pretty useless, like:

/**
* Doing something
*/
fun doSomething()

And some comments can be resolved by increasing the readability of the code.

Instead of:

/**
* Returns time in milliseconds
*/
fun currentTime(): Long

you could write one of:

fun currentTimeMs(): Long
fun currentTimeMillis(): Long
fun currentTime(): Duration

But there are cases when you most need to understand, not WHAT, but WHY

Why did you apply this hack? I’m pretty sure not because you have a lack of experience. You made some investigation, and you stuck with some problem. But now instead of committing the whole flow (what you tried to do, why, and why it was not working, and why your hack is working, and where you took that), you just leave a nacked piece of code, that looks strange without knowing the context. And now there is +1 riddle for the new joiners.

Or let’s say you made some custom view, that shows a text with some specific centering or other behavior. It is hard to write that in the just name of the class. I’m pretty sure you agree, that the name TextViewThatShowsTextInSpecialCentricWayBecauseOriginalHasNoSuchBehaviour is too much. Instead, you can use some CenticTextView or SpecialCenticTextView and describe in java doc what is special. Sometimes you can draw some block schemes or examples in the text, which really helps:

spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
//magic formula to be able to display things like
// ________________________________________________________
//| | | |
//| | Item 3 | |
//| Item 1 |__________________| Item 5 |
//| | | |
//|__________________| |__________________|
//| | Item 4 | |
//| Item 2 | | Item 6 |
//|__________________|__________________|__________________|
//
//with ratio 3:2 (bigger height to smaller height)
return SOMETHING_NEW_SPAN_COUNT / 2 + (position + 1) / 2 % 2
}
}

5. You commenting not working tests

Tests are important. Even more important is to maintain tests. Tests should be always concise enough, isolated, repeatable, independent … and not commented!

Really I thought, I will not see this anymore. But from time to time, a project to project I was faced with tests that were commented. Or even PR, where those tests were commented. Sometimes, you delete functionality and tests should be deleted. Sometimes you change functionality and you change the tests accordingly. But not commenting them out.

--

--

Michael Spitsin

Love being creative to solve some problems with an simple and elegant ways