TDD, Linters, Code reviews, Static typings, are soo overrated, prototype fast without fake safety
I was C# back-end developer for many years and I had only that perspective. Since few years till now I moved to front-end and I really appreciate that switch. I was involved into project with some Ruby on Rails guys. That was really eye opening experience. I found out that you can effectively code without super heavy IDE like Visual Studio with Resharper. You can just use VIM. You can scaffold pretty quickly some common stuff like background running process with few commands. Something that would take me plenty of work in C# like creating background service to which I can delegate long running tasks from ASP.MVC and communicate back progress via database, with Ruby on Rails was easy-peasy. I switched that time to CoffeeScript and released that I don’t miss static typings that much. What I get from CoffeeScript — readability was much more beneficial to me than auto code reformatting etc. In your everyday work you most often read your code or someone else’s code, than write your own. It’s why readability of code is much more important to me than better intelisense/autocomplete or code reformating.
There are few things that came from back-end developers and in community are considered as something that you must to use or you are lame otherwise. Moreover most of boilerplates, seeds are initially set up with all these tools. And in real world you don’t need so many tools, seriously:)
It’s one of the most overrated techniques. What I released it’s a little bit like with the analogy of Big Data to teenagers’ sex. Everybody is talking about this. Everybody is telling you should feel yourself ashamed when you don’t do this. But in reality, very little people do it. Even a smaller part of people is doing it in a right way. Few myths about TDD below:
- “it makes you more safe during refactoring”
It’s one of the most common myth about this approach. In reality it makes your refactoring much harder and painful. Unless you are doing some small refactors like name changing, then really TDD is for you ;). Most likely when you are developing something, you don’t have big picture of what you really need. Your vision is often changing and when you finally build thing up from small pieces, you actually start to have better picture and then, you should rearrange your model to fit better to the reality. So let’s imagine, you are developing some file analyzer tool, you scratch your head and suddenly came out with some brilliant ideas. Oh yeah, that’s gonna be factory which produces file parsers, then these parsers will be injected into file interpreters and so on. You are writing small test to test if your factory is working. Then you write your factory and tests for parsers etc., etc. You assemble whole thing together and realize that it’s kinda working as you wanted. But — it’s not a proper model and maybe chain of responsibility patter would reflect your needs better. At that point you have your solution covered with concrete of unit tests. Additionally you made so much effort to get your reporter showing to you that you are good guy and you have 100% test coverage. You are a hero of the day! And then you wanna refactor your model what means that you gonna have to delete all your precious tests and write them again for chain of responsibility… Will you do so? The answer is obvious. You are not willing to do that hardcore refactors and your code model is moving away from reality more and more. If you do not have these tests to be maintained, you move faster, you are willing to experiment more to build prototypes to find out if your concept was really right. That’s, for me, proper flow of development. Build a prototype without taking care of code quality and after that build it up again with a good quality.
- “it makes your code better, because you need to think of testability which enforces best practices like SRP and IoC”
It’s also something I would argue with. Unit tests are low level, which means you are starting reasembling your concept into small pieces. Then you test such small pieces separately and assemble solution out of these pieces. That’s bad approach... You should always go from higher to lower level, so you should define your needs first. When you build a component or service, first of all you need to define what is your imaginary API for that component. How you wanna invoke this component, what parameters it needs to get and what result it should produce. Then you should go deeper and deeper. Like UX requirement should define UI, which should define component markup, which should define controler ,which should define service, which should define API which should define back-end and finally database. When you start building up from the bottom up you will end up with small pieces well tested but not matching together.
- “it makes you develop faster, cause you don’t have to reproduce all steps like going to browser and click this and that to find out, if your component renders properly”
I partially agree with that. When you test your services, when you have some typical business logic functionality, some computation stuff — that’s great case for unit tests. I am writing some tests during development of this business logic to do not open it up in a browser every time, but than I remove such test from the solution, when I am done. I do not want any test to stop me from refactoring this whole thing from the scratch.
2. Linters and other static code analyzers.
There is an opinion that these tools will let you keep consistency across your project. When different people will jump in, they gonna keep the same coding style. It has nothing to do with reality, it only forces you to keep appropriate number of spaces between parenthesis and use single quotations for string and other unnecessary things. When one team member in your project is in favor of functional programming, the other is a big fan of SOLID principles and another 2 are juniors who don’t care and just write whole logic in a one big function, — it will result with mess in code even if you are using Linters. Downside of this is that it’s gonna make your IDE slow. It will pollute your IDE with plenty of styling errors and warning, which will distract you while coding.
3. Code Reviews
They can be beneficial, but only when a person who is doing them has this capability to catch some typos or other mistakes. Of course, it can also help junior developers to catch up with senior, who is doing code review picking up some bad code quality and places to improve. Still, the cost of this is pretty damn high. Every time you have to judge for yourself if it’s beneficial for you or not. When you have strong pull request policy to go through review process, before every merge to master branch, it will cause some problems. Anytime you wanna push something pretty quickly into dev branch you have to ask some of your friend to do a review for you. Most of developers are working in some kind of flow mode and it’s very hard to get into this mode and also very easy to get distracted. When you receive few pull requests during the day while you are inside flow mode and someone even is standing at your desk asking for review, — that could be super annoying and time wasting.
When you are in rapid development mode and you are building green field project from scratch, very often things are changing. Requirements are changing pretty quickly and you are writing something, than removing it, than writing again. If you are at the same time learning new framework like angular 2, it’s very often that you rewrite your code over and over because you are still learning. It has no sense to be so tight into details and waste a lot of time for code reviews and get into discussion if this should be extracted into method or not.
4. Static typings.
I think that with “static typings” it’s all or nothing situation. When you have dynamic typings like you have with typescript, it has all downsides of static typings with very little benefits. The place where static typings shines like in C#, is refactoring. But you have to have types as mandatory everywhere, not like in TS. You can change method name or extract something using Resharper and you are safe. yYou know that nothing will blow. With typescript I don’t see much difference with refactor, if I am doing them in WebStorm in ES6 or TS. Always, I need to go through the list of places where resharper has found occurrence of method I am willing to change and I need to go through this pretty long list and waste time for verification.
Downsides with which typescript is coming with is obscuring readability. As I said before, you more often read code than write it. When your code is overpolluted with generics, with casting to types, it makes it much less readable. Below, you can find an example of the same code in TS in ES6. For me ES6 example is much more readable.
I am curious of your opinions on that matter. Are you using TDD for everything and you are happy with it? Maybe I will make approach no 10 for this and finally love it;) For now I am living happily without it.