Developer's blog

Go to Notes

Overengineering

In the modern, world there are a lot of different libraries and tools which were created to simplify software development, make it faster and less error-prone. Let’s talk about frontend development. 10

Such an approach requires complicated frameworks like React or Angular so the size of vendor.js is measured in thousands of Kb. It looks reasonable when we talk about big enterprise applications but for a simple resource it’s strange. I’ve seen a lot of situations when developers tried to solve consequences of this problem but not the problem itself, i.e. they configured code splitting for big vendor.js instead of refusing using complicated libraries which actually are not required for the project of that size.

Almost every popular framework or library requires a lot of dependencies, i.e. today I’ve created empty Angular application using ng new command and it has 1143 dependencies. Furthermore, if you need some additional features you install some plugins with additional dependencies. So the size of node_modules can reach thousands of megabytes and application building process can take a lot of time.

If you have a fast network and high-performance computers such problem is invisible or unimportant. There is another problem which can’t be solved using better hardware, the problem familiar for every developer - overengineering. Let’s take a look at a classic “Hello world” application in JavaScript:

console.log("Hello world");

Nice and easy, but what if tomorrow I’ll need to print this text several times in different functions? It’s good practice to extract it into a constant.

const HELLO_TEXT = "Hello world";
console.log(HELLO_TEXT);

I think the logging is tightly coupled with the application logic. It’s not OK. Well known books suggest to avoid such situations, so let’s add a bit of dependency injection.

const HELLO_TEXT = "Hello world";

function run(log) {
  log(HELLO_TEXT);
}

run(console.log.bind(console));

I want my application to be extensible because I don’t want to rewrite all the code from scratch every time when requirements are changed. What if tomorrow I’ll need to send this text over the network instead of simple printing to the console? Let’s add some logger class which I can inherit from and overwrite its behavior.

const HELLO_TEXT = "Hello world";

class Logger {
  log(msg) {
    throw new Error("Not Implemented");
  }
}

class DefaultLogger {
  log(msg) {
    console.log(msg);
  }
}

function run(logger) {
  logger.log(HELLO_TEXT);
}

run(new DefaultLogger);

As you see simple one line application grew up a lot. Do you think it’s easier to read? Do you think this application solves some new problem? Do you think this application will cover all new requirements in the future? The only thing I see is that the application became bigger and more sophisticated.

Let’s consider a real-life example. I’ve read an article about Redux and have watched video from the big respectful frontend conference about the separation of the state and the presentation. I’ve understood the importance of such ideas and now I want to integrate Redux into my pet project for the state management, Redux Form for forms management (I have only one simple form in this project) and redux-saga to make application side effects easier to manage (I have only one request to the server) and test (for now I don’t have any tests at all). From the one side if this project grows up there will be some probability that project structure won’t change and it’ll save some time. From the other side let’s take a look at what I have for now:

If you consider Redux integration as some sort of training then it’s OK, but if you integrate Redux in a small application and don’t see all these negative consequences it’s a bit strange. I can oversimplify and say that Redux is some sort of global variable with several coding conventions which protect developers from shooting themselves in the foot. But there is a well-known piece of advice being given to any junior developer: avoid global variables if you can. So why Redux or React Context is different?

I wonder why some developers see only positive sides of technologies they use. They think their code is clear and beautiful but for someone who isn’t familiar with a new modern complicated library it’s very difficult to understand anything and requires a lot of time joining the project.

Sometimes developers trust every word of famous engineers: if they say object-oriented programming is bad and functional programming is good so it is, if they say use global storage in your project you need to rewrite your application and integrate global storage in it, if someone on frontend conference says that every application need server side rendering you’d better do so.

In my opinion, every developer should think before using any of such suggestions. Maybe a famous developer works in a big company which solves its own tasks. What if these tasks require such approaches and instruments which will be unacceptable for some other tasks. Sometimes object-oriented programming can be more suitable than functional programming and the global store isn’t the best solution. One more thing, every developer even experienced one is a human and that is why can make mistakes. Blind faith in a person leads to an inability of making reasonable decisions and that is why it slows down the developer’s growth.

Another situation which I meet from time to time is incomprehension of libraries and frameworks used in a project. Almost every project use Webpack but only a few developers can say how the code of Webpack works and why. Ok, maybe such type of knowledge is too specific but almost no one even looks at the bundled file structure. Sometimes during code review, I ask developers if they took a look on a code of used libraries and the most popular answer is: “No, why do I need to do so?”

Some developers think that it’s unimportant technical details and they can solve business problems without it, but it’s not true: you can’t understand why you can’t use if/else in jsx if you don’t know how it processed with Babel, you can’t understand why sometimes Webpack during building process returns to 30% after it shows 50% if you don’t know how it performs building, you can’t write safe code if you don’t know how Webpack modules isolated from each other and so on.

Some developers can say that all this information is very interesting but they don’t have time to explore it, because every day some new instrument is released and they need to look at it to stay in trend. As I know employers always need two kinds of developers: someone with deep knowledge of a particular instrument or business field and someone who can learn such instrument very quickly. From the one side, people who don’t spend time on learning instruments deeply obviously can’t belong to the first group. From the other side, all libraries and frameworks are alike, so if you learn one of them deeply it’ll be easy to switch to another one.

Coming to a conclusion I want to underline three main points:

These points will make you a better developer.