How TypeScript can teach you web standards

Recently my team decided to migrate all views in our Angular 1.x application to React. To me, the value of React is doubled if used together with TypeScript. I enjoy developing views when I have autocompleted and static checks for the view model, used in the view. I also can safely rename elements of the view model, which I prefer doing often and after I have already worked with the model and realized what the best name could be. Moreover, JSX in TypeScript is also statically checked, so you can not make mistake there as well. All these merits are impossible in Angular 1.x and Angular 2. Both have special DSLs for describing views and of course those DSL are not as powerful as TypeScript when it comes to static type checks.

But what I have discovered is that TypeScript can even teach you web standards. These standards are not very consistent but we still have to use them correctly. Let me give you few examples.

First, TypeScript can teach you JavaScript itself and save you from silly errors. Look at this code and try to answer the questions (--strictNullChecks):

After you gave it some thought, here is the answer: the type of y is never and type of z is number | null. If you answered correctly, you are great JavaScript developer with exceptional memory. The type never is given to y because that line will never execute. This is because of JavaScript’s design flaw which defines this expression to be true: typeof null === 'object'. Having learned this, now, what are the types of y and z in the following snippet?

Well, you are totally right, y is null, because 'typeof null === 'object' is true. And since true part of the if statement has dealt with null, the type of z is just a number.

Now, let’s have a look at a second example, now TypeScript will tech us something about DOM API. Have a look at the following code, which does not compile (it used to handle React button click event):

What??? This way official React’s page teaches us to access values from the event targets!

React docs snapshot

When we first encountered this problem, we decided there was a bug in TypeScript type definitions for React (those are installed with npm install --save-dev @types/react). But later we discovered, those type definitions actually have another property for SyntheticEvent<T> (type of target), named currentTarget, whose type is different:

Hmmm, let’s see what dumentation has to say about currentTarget:

Identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed to which identifies the element on which the event occurred.

While target is

A reference to the object that dispatched the event. It is different from event.currentTarget when the event handler is called during the bubbling or capturing phase of the event.

So are we interested in the value of the element where we placed an event handler or in the element, which dispatched the event? target is the origin of the event, which no one really cares about, it might be a span inside a link, for example, while currentTarget is something you should very much care about, as this is the element, to which you have attached your event handler. See more discussion on this topic here . We have learned this only because TypeScript caused us to dig deeper into targets and see the difference. Without it, we would have used target and wait for problems to come (someone might place child element to the element we were listening to and target would become this child element!). So, thanks, TypeScript and those great people who write type definitions for lessons :-).


Few guidelines on unit testing derived from my experience

When I first started using unit testing in my practice, I had no idea what I was doing. I was also frustrated. It made little sense to me to have everything unit tested because writing tests and preparing test data took me too much time.

Ever felt the same way? Don’t understand where and when to write test and where you should leave the code alone? Don’t worry, this is normal. This happens to everyone who tries to improve the way he/she does software. I can’t give you a concrete prescription, no one can, but in this post, I will share what worked for me in terms of unit/automated testing. This will, probably, work for you.

Don’t write unit tests for simple cases. One objective way to measure the return on investment (ROI) from unit tests is to measure how much time they save for development team by catching regressions. In simple cases, when the code is not going to be changed or code is pretty straightforward it is unlikely that you will get regressions, therefore it is likely that you will have no ROI at all from your unit tests. Furthermore, you will need to maintain them. The law of diminishing returns works here. You can get 80% of the benefit from covering only 20% of your code with tests. This 20% of code contain your core business logic, which delivers the most value to your customers. Everything else is some kind of glue code, configurations, mappings, frameworks, libraries interoperations and so on. The more effort you put to cover this code, the less ROI you will have.

Do large acceptance tests for refactoring. If you plan to do some large refactoring or restructuring, classical unit tests will not help. In fact, they will go into your way. Classical unit tests are small and test some small parts of the system. When you start changing things, unit tests start glowing red and you will need to delete them. The large acceptance test captures the whole business case of interaction between your system and the user. Such a business case is something that brings real value to the business and should not be changed during refactoring. Relying on acceptance tests will increase your chances to refactor without damage to the business. In developeronfire podcast, Nick Gauthier (episode 149) reported that he had his largest success in the career by moving the web application he worked on from classical client-server architecture, where HTML was rendered on the server, to the single page application (SPA). Acceptance tests made transition really smooth for his team. My refactoring team at SimCorp also had a big success of not jeopardizing our product’s quality by major refactoring we did. That refactoring touched almost every user screen in the system. My team lead insisted on having large acceptance tests suite, which eventually ensured our success.

Unit test complex algorithmic stuff by classical unit tests. As you probably know there is classical and London school of TDD. According to the classical school, unit test just applies input data to the system under test, harvest the results and compare them to expected results. According to the London school, unit test invokes system under test and then checks if it behaves as expected, i.e. it calls its collaborators correctly and in the correct order. While I feel frustration from unit testing simple cases, I get a lot of value from classical TDD when I develop complex algorithms. Value, in this case, comes from regressions which happen during initial development, because when you develop a complex piece of software you can potentially spend days in one unit trying to put things together. I vividly remember one programming exercise from my SimCorp days. I had to develop a program, which would take APL data structure of any complexity (for instance matrix of matrices) and generate APL code which would recreate this particular data structure. My first attempt failed because after 4 ours of work I was far from being done. And most of this time was spent on retesting program operation with different types of inputs after every change to the algorithm. Next day, I have tried classical TDD. And the process was not only fun but also fruitful. In about 4 hours I was done with approximately 30 tests. I remember my impression was that I would not have finished such a program in this amount of time and confidence without unit tests.

Apply London school TDD to the integration code. What if your core business logic is not algorithmic one? What if you bring the value on the table by integrating different systems together? For a very long time, it was an open question for me. In such a cases I still want to be sure my core code is tested well. However, classical tests are awkward because integrators often don’t even have inputs or outputs. I believe London school tests are perfect for them. Once, at StrategicVision, I had to develop a system that would download videos from video hosting services, extract audio from those videos, transcribe audios and finally save transcriptions and video links to the database. No business logic in a classical sense, right? My code just invoked video hosting web service, then invoked downloader, then invoked transcription web service and finally invoked repository to store results. I wrote a bunch of tests which were testing, for instance, such facts: if the system under test invoked downloader for a particular video, it should later invoke clean up for this video; if the system under test invoked database repository to store results, before that it should invoke transcription web service.

These guidelines are highly subjective of course, but at least they work for me, at least at this point in my career. Hopefully, you will also find them helpful.


Віддалена розробка програмного забезпечення (Вебінар)

Вчора продовжив свою вебінарову подорож. Цього разу вирішив зробити експеримент і провести вебінар на не технічну тему та зі співавтором, Анею Зубенко, у формі інтерв’ю. Вийшло класно, дещо розтягнуто, але це ж було інтерактивне інтерв’ю і ми намагалися невимушено обговорити багато тем та відповісти на більшість запитань, що глядачі задавали. Словом багато фану, судячи з коментарів у чаті під час вебінару, народ теж отримав позитивний заряд! Там більшість інформації – аудіо, тож цілком можна його вилучити та послухати в навушниках по дорозі кудись. Приємного прослуховування!