Developers Club geek daily blog

1 year, 10 months ago
imageI want to share the small positive experience about the project Typescript based on Angular + after a year. It is not a new sheaf, and I am sure that already many successfully use it. Of course, already many wait for more articles about React or Angular 2.0, but it seems to me, and this experience will be useful to someone.

Context


I work in product company. The main product is a corporate application and history of 10+ years (Web, ASP.Net, C# MSSQL). Despite honourable age and codebase 1M+ LoC, the project still actual, supported, both refactoring and updates of libraries and approaches are systematically carried out.

But here the client wanted to make replacement of the main UI by SPA (Angular) that it worked at devices. — And the new project began a year ago.

Before I worked as the architect at part backend C#, and worked on business rules, SQL-performance, SQL-deadlocks, queues and tp.

With Javascript actively worked only at the pet-projects and the code amount was not considerable. One pet-project I even had to transfer from javascript on java (GWT a traslyator) after 15k to LoC! Because of the fact that the project stopped being supported. Heavy transition was repaid (Angular did not appear yet).

Therefore, it was difficult to me to provide as it is possible to write javascript the project with> 20k to LoC and at the same time to preserve it podderzhivayemos, readability and expansibility.

After the analysis of our current similar SPA projects on Backbone, Angular I was once again convinced of it — they had on 20k-35k LoC, the structure was, but not accurate, any refactoring in them was already not possible.

Requirements


Requirements of new Angular of the project were evaluated as 2-4 times big to current.

Moreover, in requirements support of HTML5 Offline mode was also required at what with support of editing data (and it means that except REST we still have to have similar implementation on IndexedDB).

Start of the project was planned in one or two months. Therefore I had rather calendar time for research of the current experience of the current javascript command and an input in javascript — Angular, new to me, an ecosystem.

Decision-making


Angular

Even it was not discussed. We had a command with 1-2 years of its use. The client insisted on him. It imposed me also after my davny experience with pure jQuery, GWT UI, heavyweight UI Toolkits — seemed a breath of fresh air.
Knockout, and old-kind Backbone demanded creation of model on the obyektakh / methods. I it gorged on such "restrictions" wholly before. The possibility of use of Plain Javascript Objects/Arrays in Angular was outweighed by any performance of benefit Knockout, Backbone.

On the other hand Angular have features — DI and overdesign.

Service, Module — unit of structuring a code (like a class), Factory, Controller is a sugar around Service. I not really wanted to use Angular DI which to the same completely confused WebStorm 9.

Typescript

Tried the main solution which I long deliberated, prototipirovat and advanced before the client. By the way, it was rather difficult to speak then to the client (and command) why we have to write in other language, but not on Javascript which to a trend, especially on the strategic project calculated on years.

It is important to understand the main message — Typescript is NOT other language, this Javascript expansion (just as LESS — CSS preprocessor).
It is also important to understand why in general we need Compile-time Type Checking (by analogy with C#, Java, C ++):

  • Does elementary checks of a correctness of a code, otherwise — it is necessary to write hundreds of elementary Unit-test which add the size to the project and break at any change in the application.
  • Does possible refactoring, change of structure, merzh a code possible and controlled
  • Support of IDE is usually much better — and it is the high speed of development. In any place of a code you cause auto-complite after "." also you see 5-10 options, but not 100 approximately possible. Find-usage really works, in IDE search in user.id will not mix with product.id
  • The developer starts the heavy application less, IDE, grunt build warns about simple at once, and sometimes difficult errors
  • Simplifies revyyu / the analysis of a code
  • It is especially actual for big projects (by my experience> 10k LOC)

From my point of view, Typescript killer-feature — optional typification.

When I worked with GWT (there you write on java in the IDE, and the compiler converts it into javascript), tired me that EVERYTHING, each variable it is necessary to mark with type, it costly and it is not necessary. There is a wish to designate types only some things in the application (contracts between modules, data and their converting in model, arguments and return of functions tp).

By the way, C#, Java, With ++ move to optional typification too — var, auto, dynamic.

If just to copy strict-Javascript a code in Typescript the file — that is compiled without problems. If check of types is not necessary — just led to the special any type, and all is possible:

var a=<any>0; //вариант 1
var a:any=0; //вариант 2
a().some().thing()[15].else();

Support of Generic-types is especially convenient (just as C# and Java), together with ES6 Arrow functions all prebrazovaniye and work with promisa and model it is extremely readable and safe, and it saves this:

function loadUsers():ng.IPromise<Array<User>>{ /*some*/}
function loadBirthDates():ng.IPromise<Array<Date>>{
    return loadUsers().then(users=>users.map(u=>u.birthDate));
}

Here IDE accurately knows that u — has the class User, and will give an error message if there is no birthDate there or it has not a Date type.

Support of ES6 class in Typescript.

At first sight ES6 class is a normal sugar (on the example of babeljs, Typescript of the compiler which generates prototype). But here it is not runtime, here matter in support IDE and millions of programmers conceiving more in OOP, but not in Functional style.

Example 1:

function a(){
 function b(){
    function с(){
       function d(){}
    }
  }
}

Let's say that this code is written in OOP style where here the module where a class and where a class method? And all this can a class in inside it private a method b in which with? Perhaps an example and far-fetched, but occasionally so too make out a code, as well as through prototype.

Example 2:

module a{ 
  class b{
     c(){
        var d =>{} 
     } 
  }
}

Here levels in the terms OOP are already clear without explanations. And, they are clear not only to the person but also IDE. And IDE already precisely knows what is, that.
Readability is many times higher though it is compiled in all same nested functions.

Also in difference from GWT, Typescript is compiled on-faylovo with saving of all indents and comments (in WebStorm — on saving of the file). I do not include source-maps in Chrome when viewing Typescript of the file — the generated JS file a little in what differs.

Also in our Backend to command all know С# and OOP. And uses of Typescript — does possible their rotation on Frontend (knowledge of CSS and imposition not crucially, I will repeat at us the corporate application).

Structure and implementation


The structure of the project looks so:

  • framework
  • business
    • security
      • dto
        • UserDto.ts
        • GroupDto.ts
      • dal
        • SecurityAdapter.ts
        • SecurityOfflineAdapter.ts
      • SecurityFacade.ts
  • ui
    • security
      • SecurityController.ts
      • Security.html
      • SecurityMobile.html
  • routing
    • routingStates.ts

framework "sees" libraries, business "sees" framework and libraries, ui and routing see everything.

This structure and agreements is selected not accidentally, she reminds our ASP.Net the project to which all in backend-command got used. Can pull it from backend in SPA will seem strange, but parallels and convenience of developers are obvious to me.

Standard Typescript support of modules is used (though there many options are available): import(s) at the beginning of the file and _references.d.ts files. Not really convenient solution, but clear IDE, I think that we will pass to what that another if IDE understands it.

Ui a layer addresses business only through * Facade classes.

Typical Facade is a class in which practically all methods return promisa. Facade is responsible for Adapters challenges inside.

///<reference path="../_references.d.ts"/>
module business.security {
	export class SecurityFacade {
                loadUsers():ng.IPromise<Array<UserDto>>{}
                loadGroups():ng.IPromise<Array<GroupDto>>{}
                renameUser(userId:string, name:string):ng.IPromise<void>{}
        }
}

Offline support is simple to be performed, for example SecurityFacade.loadUsers is implemented so: we cause SecurityAdapter.loadUsers — if promis returned an error — we load from IndexedDb SecurityOffineAdapter.loadUsers if that is successful we cache successful result in IndexedDb — UserOffineAdapter.saveUsers. There are many parts (for example queues on saving, a limit of Indexed DB and tp), but roughly works so.

///<reference path="../_references.d.ts"/>
module business.security {
	export class SecurityFacade {
                loadUsers():ng.IPromise<Array<UserDto>>{
			SecurityAdapter.loadUsers().then(data => {
				SecurityOffineAdapter.saveUsers(data);
				return data;
			}).catch(ex => {
				if (isOffline()) { return SecurityOffineAdapter.loadUsers();}
				throw ex
			});
                }
        }
}

The solution not to use Angular DI is possible, non-standard. Even without special need for Angular on business, to us to have to wrap all promice types (napr jQuery) and raznoshostny onSuccess/onError in Angular promice. as well as any other provider it is easy for $q to receive out of Angular DI:

var $q = angular.element(document.body).injector().get("$q");

Any objects kept in Json after loading and before sending are surely checked Adapter-ohm. Typescript will not help you with it. Therefore in each Dto a class we have copyAndVerify the static method which can inside checks and clears each property of object and also causes it in subobjects, and also can make "upgrade" of object up to one version higher (for example renaming of a field and change of type). The challenge of copyAndVerify does Adapter for each object in a collection. When saving it is also necessary — Angular hangs the methods on object which need to be cleared before serialization, and also Angular of the directive can replace type — for example to save number as the text.

UI: SecurityController is a normal class too, only it to be registered in Angular, and also selects the necessary view.

///<reference path="../_references.d.ts"/>
module ui.security {
	import SecurityFacade =  business.shared.SecurityFacade;

	export class SecurityController {
                users:Array<User>;
                constructor(public $scope:IScope, public $window:ng.IWindowService) {
                            new SecurityFacade().loadUsers().then(users=>this.users); //Arrow-functions позволяют не писать var _this=this; 
                }
        }
       
        // @ngInject
	function SecurityDirective ():ng.IDirective {
		return {
			scope: {},
			templateUrl: routing.isMobile() ? 'ui/security/Security.html' : 'app/security/SecurityMobile.html',
			controller:SecurityController ,
			controllerAs: 'securityCtrl'
		}
	}
        angular.module('app').directive('securityDirective', SecurityDirective);
}

A year later


Are happy with a sheaf. In the prodakshena already half a year. Already near 23k LoC and at the same time the project easily endured 7 average refaktoring, change of command. It continues to be easily supported, we are going to add the next big feature soon. Recently changed IndexedDb to a lib for the. It is easy for Code-review to carry out.

It was necessary to tinker with support of offline, but 200Mb we store easily on all iPhones, iPad, Chome, IE10. Plus, all by SPA (2,5Mb) to be loaded from a local cache therefore starts smartly regardless of Internet connection.

To come periodically to pay to performance on Angular attention — to clean watch and to replace with events, to review directives and the views code.

Autotests, by the way, are written on Typescript with use of Protractor and PageObject of approach too.

Now Typescript is supported perfectly in WebStorm, the Visual Studio (in 2015 it is already good) and some other probably. If selected now, can selected - React instead of Angular. Also I think partially to apply Typescript in ASP.Net on heavy UI kontrola.

This article is a translation of the original post at habrahabr.ru/post/274591/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus