Developing Large Scale Angular Apps – Lessons learned at Snapflow – Some Examples



Developing Large Scale Angular Apps – Lessons learned at Snapflow – Some Examples

0 2


AngularJS-Portland-Meetup-Slideshow

A talk on how to build a large-scale application in Angular. Lessons learned at Snapflow.

On Github Snapflow / AngularJS-Portland-Meetup-Slideshow

Developing Large Scale Angular Apps

Lessons learned at Snapflow

Created by:

Jameson Nyeholt | github.com/wintermuted

Snapflow | snapflow.com

  • Introduce yourself.
  • Introduce Snapflow. Cloud platform for the modern enterprise.
  • Explain the topic
  • Purpose is to explain some of the lessons we learned building our front-end platform and a customer project using Angular.

What this is about...

  • Problems encountered when scaling from seed to delivery on large apps.
  • Best practices learned from resolving these problems.
  • Some things you probably already knew about web app development and Angular.

What this isn't about...

  • A guide to being an Angular Ninja.
  • A tech demo.
  • A solution to all of your problems.

Some Context

  • Snapflow is developing a BaaS product.
  • A large part of our offering is a UI that allows engineers and non-engineers to easily build applications.
  • Timeline:
    • Platform Development began in early 2012.
    • UI Development in Angular began in late 2012.
  • If someone doesn't get this, mention Force or Parse.

More Context

  • Our MV* of choice is Angular, but we also make use of jQuery for our more complex "builder" UI that Angular isn't well suited for.
  • Development started when Angular still had pretty terrible documentation (1.0 - 1.0.8), and the infamous comments section.
Sidebar: Angular recently updated their documentation. It is much better now.

Some Examples

More Context

  • 50+ Routes and Controllers
  • 100+ Directives
  • 15+ Services
  • Integrations with JsPlumb and various other libraries.

A re-introduction to Angular

The Zen of Angular

  • "Angular is built around the belief that declarative code is better than imperative when it comes to building UIs and wiring software components together, while imperative code is excellent for expressing business logic."
  • Source: http://docs.angularjs.org/guide/introduction

What Angular is good for (High Level)

  • It lets Front-End teams move fast.
  • In general, is very performant for CRUD-style apps.
  • It scales well, if code is written well.
  • It tests well, if code is written well.

What Angular is good at (Low Level)

  • Two-way {{data.binding}}
  • Templating done right
  • Program flow for CRUD is easy.
  • Initialization and basic services "just work"
  • Dependency Injection
  • Highly testable (if you write TDD code)

Lessons Learned

Common Angular Pitfalls

  • Two-way data binding makes us lazy
    • There is a tendency to set everything to $scope
    • Tendency to use DOM/View as Model.
    • There is a tendency to do development entirely in Controllers, especially during initial development.
  • Agnostic file-structuring can lead to poorly organized projects.
  • Not adopting TDD from the beginning.

Things We've Learned

  • Code & project organization is very important
  • Properly organizing app concerns from the beginning is important
  • $scope can be abused.
  • TDD from the beginning is a must.

Code Organization & Project Organization

Have a project structure

  • Angular doesn't care how you organize files, but you should.
  • Poor file-structure leads to poor code organization.
  • Poor code organization leads to spaghetti.
Maybe provide an anecdote.

Have a usable project structure

  • Project structure should be constantly evaluated.
  • Don't start with a grand design. Evolve it.
  • Self-documenting project structure is as important as self-documenting code.
  • Having a single folder called /scripts, /controllers, or /services will not be suitable as the project grows.
  • Examples of Angular Project Organization:

Suggested structure from Brian Ford (Angular Team)

                           
root-app-folder
├── index.html
├── scripts
│   ├── controllers
│   │   └── main.js
│   │   └── ...
│   ├── directives
│   │   └── myDirective.js
│   │   └── ...
│   ├── filters
│   │   └── myFilter.js
│   │   └── ...
│   ├── services
│   │   └── myService.js
│   │   └── ...
│   ├── vendor
│   │   ├── angular.js
│   │   ├── angular.min.js
│   │   ├── es5-shim.min.js
│   │   └── json3.min.js
│   └── app.js
├── styles
│   └── ...
└── views
├── main.html
└── ...
                           
                        

Source: http://briantford.com/blog/huuuuuge-angular-apps.html

Be Mindful of file content & Naming

  • Each file should contain one Module.
  • File names should correspond to the Module they contain.
  • Directives namespace should be prefixed to avoid collisions with other libraries like Angular-UI or Angular-Strap.
                        
// snapflow/app/core/controllers/users/UserManageCtrl.js

angular.module('SnapflowApp').controller('UserManageCtrl', function () {
    // ...
});
                        
                        
                        
// snapflow/app/core/directives/pickers/UserPicker.js

angular.module('SnapflowApp').directive('sfUserPicker', function () {
    // ...
});

<div sf-user-picker="params"></div>

                        
                        

Separating Concerns Properly

Following the Zen of Angular

  • In initial development and smaller apps, it is easy to get away with writing code in Controllers, but this is a bad practice for larger apps.
  • Angular provides Controllers, Services, Filters, and Directives for a reason.
  • Our code should be logically divided amongst these.

Some Guidelines

  • Handle state logic in Controllers and communicate to Services and Directives
  • Handle UI logic in Directives
  • Handle business logic in Service/Factories/Providers.

Give code a logic, modular separation of concerns.

                            
angular.module('SnapApp', ['ngResource']);

angular.module('SnapApp').factory('restService', function () {
    // Service Factory for interacting with the REST layer.
});

angular.module('SnapApp').factory('cacheService', function () {
    // Service Factory for interacting with the in-memory cache.
});

github.com/Snapflow/AngularJS-Portland-Meetup-Slideshow


angular.module('SnapApp').factory('appService', function (restService, cacheService) {
    // Service Factory for managing apps and the interacting with the cache.
    var service;
    service = {
        app: {
            get: function (appId, callback) {
                restService.app.get(appId, function (appResponse) {
                    cacheService.app.cacheApp(appResponse, function () {
                        callback(appResponse);
                    });
                });
            },
        }
    }
    return service;
});

angular.module('SnapApp').controller('appController', function ($scope, appService) {
    // Controller for allowing the user to get apps.
    $scope.app = null;
    function getApp(appId, callback) {
        appService.app.get(appId, function (response) {
            $scope.app = response;
        });
    }
    $scope.getApp = getApp;
});
                            
                        

Suggestions for Approach

  • You might start with low-level implementations, or high-level implementations (services/factories vs. controllers).
  • The most important thing is to constantly evaluate and refactor.

With great $scope, comes great responsibility

Two-way Data-binding is a shiny object

  • Template bindings to $scope is one of the best features of Angular, but is often abused.
  • The initial tendency is to assign everything to a $scope variable during the initial prototyping of UI.
  • When writing larger scale apps, be mindful of bad use of $scope.
  • Over-use of $scope can lead to the bad practice of DOM as Database

TDD or die.

Big Web Applications need Testing

  • These aren't websites. They approach the complexity of some back-ends.
  • Unfortunately, often testing on the front-end is put off until the last minute, when the pain caused by the lack of tests is the most apparent.
  • It is very difficult to refactor large code-bases to be testable.
  • Within Angular, services are relatively easy to test.

Best Practices

  • Get your product team on board with testing.
    • The additional time spent writing tests will pay dividends.
    • A pushed out delivery schedule now is better than a pushed out schedule later.
    • The additional time spent will be less now than later.
  • The best approach is to write tests that mimic the acceptance criteria for feature stories, and then write code that pass the tests and full the criteria.

Final Thoughts

  • Big SPA's deserve as much architectural planning as the back-end.
  • Testing should be an integral part of any architecture for large-scale SPA's.
  • Angular is a great framework for scaling large SPA's, if used properly.

Slides

Slides are available at:github.com/Snapflow/AngularJS-Portland-Meetup-Slideshow

That's All!

We are currently hiring:

  • Javascript Engineers
  • Front End Engineers
  • Dev Ops
  • Senior Software Engineers (.NET/ C#)

http://www.snapflow.com

Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard).