
Imagine that you are a JavaScript, Ruby, Phyton or PHP developer. Your programming language does not look for errors at compile time. Actually, he has no compilation as such. If you make a syntax error, you will, of course, know about it. When run the program.
If you are a responsible developer, write the tests yourself. So do all the responsible developers. But
what will you test?
You might want to make sure that:
')
- Functions will behave properly, despite invalid arguments — for example, null, or other unexpected types of arguments.
- Optional function parameters have the correct default values - in cases where the caller does not specify these values.
- The function is located in the correct module and can be called.
Of course, you can check out a lot of things. For example, does the code do what it is supposed to do? In my experience, regardless of the language, such tests are necessary. But this is not all that I want to talk about today.
Additionally, you can make sure that the code:
- It has no syntax errors.
- It works in all environments that interest you (for example, in different browsers).
- Correctly uses libraries (for example, confusing ORM APIs).
You will not lose if you use the linter. True, his help is not enough.
Developers often try to test the entire code. They take tools that help track which lines of code are executed during tests. A full check means that each line of code will be executed by at least one of the tests.
With programming languages that I listed above, you always have to test everything to the maximum. If you have few tests, then get ready for a dialogue with a personal imp: “Do you remember that you do not have a compiler? Your compiler is your tests. Either you test everything, or you release the non-compiled code. No need to be a bad developer! ”
I tend to listen to this voice - because I don’t want to be a bad developer.

Periodically, I breathe deeply - hopefully see the light. And when I do this, it becomes clear to me that I am implicated, perhaps in the largest waste of energy in the history of man.
I used to write code in C ++ and Java. Just they have something called "compiler". That is, a tool that, among other things, checks the code for syntax errors. Before the program starts for the first time. It is still a novelty in the world of web development.
The compiler can be treated as a simple unit testing system. She guarantees that:
- 100% of your code will be without syntax errors;
- 100% of function calls will call functions. And those that exist.
If the public low-level library API changes, your compiler will not forget to inform you about this before you run the program. If you rename a function, the compiler prompts you to update the name also where it is being called.
For each function that I wrote in JavaSript / Python / Ruby / PHP, I had to write unit tests to check all this. Not even that. Worse. I wrote a separate test for each place of the function call, which checked whether it is called in this place. So that you understand - if I have a function that is called in 10 different places of my code, I have to test not only the function, but also all these ten places.
Translator's note: in fact, this is not the case and the unit test tests the “unit”. But in the context of the article, if we consider unit tests as a way to add static checks for dynamic languages, we can make this assumption.This is O (N) guys.
If any developer refactor my code, and my tests stop testing the same ways of code execution, then I will lose the benefits of these tests and never know about it. I'm sorry brother
Brothers programmers say "Forgive" and shrug their shoulders.
Does the compiler completely replace unit tests? Not really. The meaning is different. If we choose a programming language without a compiler and compensate for this by writing a lot of tests, we repeat what some very cool compiler developers have already done. Just think. If I write code on Go, then from tests that I
do not need to write , you can fold a small mountain. The compiler developers on Go have already done it for me - for every project on Go that will exist.
I'll tell you a funny story. A few years ago, my friend switched from javascript to go. He wrote some code, and then tried to write a test that would check that the code behaves correctly with the wrong type. He struggled with the compiler for a long time. I have not realized yet that such a situation is, in principle, impossible.I do not claim that Go is the only correct language. All languages that have a compiler work this way. Even languages with a terrible type system like C ++ also work this way. You do not need to be an experienced Haskell developer to get all the bonuses from this concept.
...
Whenever you write a test, think: if the compiler can make a check for you, do you need to do it? Postpone work and think about life priorities. About those smart compiler writers. They are trying to help you. Perhaps they should allow it.
Epilogue.
Then you can not read.
I warned.
Fortunately for JavaScript developers, the community saw an imminent threat - and prevented it with the help of
Flow and
TypeScript tools. But since these tools use
gradual typing , you can never be completely sure that each line of project code “takes everything” from the type system. Yes, they help. But since they are interoperable (or are an add-on over) JavaScript, you do not need the 100% "safety net" that the compiled language gives you.
More advanced type systems can go further. For example,
Ada can provide a
check on the value of numeric variables at compile time . It can even prevent indexing an array with a number that is obviously larger than the dimension of the array. At compile time.
Haskell also has several powerful typing concepts. The Maybe type tells the compiler that the value can be empty (the analogue is null). And any code that uses this value should be notified of this, or a compilation error will occur.
Webpack and
Browserify JavaScript
build tools can help a lot with this problem. If you do not have type checking at compile time. For example, if you have a syntax error in your javascript, the webpack will throw an error during the creation of the bundle. It is very useful.
Congratulations to those who read between the lines, and understand what this article is about. There were covert words against dynamically typed languages. In fact, I am calm about these languages. But negative side effects when testing can be costly to the developer. Of course, there are other negative effects that make statically typed languages costly: build time, overly verbose interfaces, search for paths, where / what lies, and so on. Some statically typed languages (Go) solve these inconveniences better than others (C ++).