Functions: this error is more expensive than "null"

Every day we use a programming pattern that unnecessarily increases the cost of creating and maintaining software. It leads to countless bugs and security vulnerabilities. It requires constant refactoring. It's hard to test, tedious to document, and its flexibility turns each implementation into a unique snowflake, leading to endless code duplication.



The name for this template is function.



More specifically, it is an interface, which is usually a collection of functions.





Which languages ​​have you learned?



One of the first when we learn programming, we learn the principle of reusable logic. This invariably brings us to function - the building block of every software project. The features themselves aren't all that bad, but it is precisely because they are used as a reusable component that writing, maintaining, and scaling software becomes so expensive.



Why?



Writing reusable code is difficult.



No, it’s not like that. This is unacceptable.



Any developer can write reusable code, regardless of their experience. Languages ​​like JavaScript, Python, Ruby, and Go are made up of millions of small common modules that demonstrate the ease of writing simple, reusable source code. It's easy to write reusable code .



Let's refactor this statement.



Writing reusable code is difficult. Difficult to reuse code.



But this is not the case either. Take a look at the node.js library repeat-string



in npm. It does nothing but repeat the line, and the developers download it seventeen million times every week.





Number of downloads of repeat-string in npm



Seventeen million is just the number of downloads. This number will not give us any idea how many times this function is used in the source code. The amount should be astronomical!



So what am I doing?



How can you find a module like repeat-string



for your node.js project? Look for "repeat string" in npm . Maybe you enter "string repeat", but the results will be similar. The problem I'm talking about can be seen in the second search result. And in the fourth, and in the ninth, and in the tenth, and in the eleventh.



Take a look at these examples. Each library provides completely identical behavior.





Examples of npm line repetition libraries



Do you see what the problem is?



No, not that one of them is asynchronous for some unknown reason. Not to mention that string repetition has been part of the JavaScript ( "A".repeat(5)



) language for over six years now . The problem is that each library is different:



  1. In the signature of the incoming data. Some may receive (string, int)



    , others may receive (int, string)



    . One accepts floating point numbers, the other requires a callback function.
  2. In the signature of the output. Every library prints out a string, except one, which prints nothing and passes its result to the callback function. And let me not even start parsing their mistakes.
  3. In the behavior when they are executed. One is asynchronous, the others are synchronous.
  4. By the method of granting access. Some provide access to a single exported function, others provide a function as a method of an object.


You can blame JavaScript for various reasons, but this is not a problem with the language. Because of the popularity of JavaScript and the limitations of its standard libraries, this problem is so common that I was able to demonstrate it with a simple example like string repetition. On the other hand, nothing prevents me from recreating all these differences in any other language. This is a very simple example, but as functionality becomes more complex, these differences become even more pronounced.



Why is this a problem?



The problem is that such a wealth of options does not create any value , but only one problem. They do not affect "business logic" (that is, what matters in the first place). These are the implementation details. Sometimes these options arise from a lack of something in the language or framework, and sometimes they are just spontaneous choices. We are trying to choose an option that will simplify the developer's work now or in the future, but it is impossible to predict the future. Such solutions are truly diabolical - each option you choose seems good at first, while everything works. We receive a dopamine boost and feel like we are on top of the world. Lords of all systems! However, when we need to add, replace or change something, we realize that we were not that genius.



How often do we need to change something? Everyday. This is what we are doing. How often does software break because of this? Literally every time. Sometimes the breakdown is minor and we fix it with little effort. We have come to terms with the fact that broken software is normal. Even when we write automated tests that do nothing but check that something is broken.



The problem with interfaces stems from the fact that a programmer can make many decisions during the development process. Decisions such as choosing between positional parameters, configurations and linkers, asynchronous versus synchronicity, global versus local, stateful versus stateless, constructors versus factories, functional versus object-oriented approach, and an infinite number of other options. Each choice is determined by modern best practices and each becomes a grain of sand trapped inside the mechanism.



This problem is not new, however, we put up with it and teach this approach to every new generation. Why? The problem is not that we make the wrong decisions, but that we are presented with bad options. Each option is a kaleidoscope of trade-offs, and the correct answer depends on the point of view. When everything is a compromise, there is always a better option . You can always rewrite your code to make it better.



Let's refactor our statement a third time.



Writing reusable code is difficult. Difficult to reuse code. It's hard to write replaceable code.



This statement is not so attractive, but closer to the truth.



Without code to just paste, we need to iron every fold of the interface before we can use it. You need to customize every piece of code that goes into the application. Every input. Every conclusion. Every API. We push linkers onto adapters and wrap them in service-based factories. But no amount of makeup will make your design pattern look pretty .



It's like we create software in the 18th century. We manually saw the trees into boards of any size. We make hammers and punch nails from scratch just to build a house that looks exactly like the next one. It costs too much and takes too long. Even after the completion of the project, we are still pulled to the ground by the burden of support. The dimensions are not standard, the wiring shocks the electricians, and the builders who have just graduated from the vocational school do not like the way we made the nails. It is high time for Leroy-Merlin and digital 2x4 to appear in the software world.





β€œHi, my name is Tim. I work as a tech lead at Google, have 30 years of coding experience, but have to find out how to get the length of a string in Python. "



For help with any API to constantly look for you personally ?




It won't come as a surprise if I say that we could have standards that are good enough for everyone. Microsoft introduced COM technology in the 90s to exchange logic between applications written in any language. The JVM technology is almost the same age, and has demonstrated how many languages ​​can handle the same bytecode and also interact with each other. The world continues to rediscover Flow for decades and Linda as a way to link distributed black boxes to each other, and Docker is a new way of looking at what a modern black box can be.



This problem presents a lot of possibilities, and many are trying to solve it. Dapr and WasmCloud look promising new solutions ... They partially solve the problem in different ways. As sad as the state of software development is today, I have more hope today than in the past 10 years. A brief period of exciting promise came from JavaScript, which promised to create a universal platform on which amorphous applications could spread around the world, but as a result, it turned into a bunch of Electron, React and wasted RAM. For me, Web Assembly has become a new source of optimism. It is far from ideal, but it is also wonderful. The ideal never wins.






Advertising



Are you looking for a server for rent for debugging projects, a server for development and hosting? You are definitely our client :) Daily billing of servers, create your own configuration in a few clicks, anti-DDoS is already included in the price.



Subscribe to our chat on Telegram .






All Articles