Guy Shahine's Blog

Behind Resoltz.com

Here’s a summary of https://www.resoltz.com technology stack, tools, libraries. I use this blog post as an agenda when I speak at events, if you’re looking for my opinion on why I chose a library vs the other, reach out to me in the comments and I’ll provide more details. An example question could be: “why did you pick Gulp over Grunt?” or “Mocha-Chai over Jasmine?”, “Azure over AWS, Google AppEngine?”

Setup

  • ASP.NET MVC 5
  • ASP.NET Web Apis
  • Asp.net identity + OWIN
  • Sql Azure
  • Azure Blob, Table and Queue storage
  • BackboneJS + UnderscoreJS
  • Typescript
  • SignalR Websockets
  • Redis Cache

Source Control

Package Managers

  • npm: Tools like bower, gulp, …
  • bower: Client side libraries
  • Nuget: Server side libraries

Automation

Gulp

var gulp = require('gulp'),
gutil = require('gulp-util'),
del = require('del'),
jshint = require('gulp-jshint'),
less = require('gulp-less'),
batch = require('gulp-batch'),
csso = require('gulp-csso'),
csslint = require('gulp-csslint'),
csslintVisualStudioReporter = require('gulp-visual-studio-csslint');

gulp.task('jshint', function () {
  return gulp.src([paths.src.scripts, '!scripts/external/**'])  
             .pipe(jshint())  
             .pipe(jshint.reporter('jshint-stylish')); 
});

// Build tasks
gulp.task('build', ['jshint', 'less', 'cssmin'])

Asp.net Web Optimization

BundleConfig.cs
var jqueryBundle = new ScriptBundle("~/bundles/jquery",
            "https://" + cdnPath + "/scripts/jquery/2.2/jquery.min.js")
            .Include("~/bower_components/jquery/dist/jquery.js");
jqueryBundle.CdnFallbackExpression = "jQuery";
bundles.Add(jqueryBundle);
In _Layout.cshtml Template
@Scripts.RenderFormat("", 
                      "~/bundles/jquery")
HTML output in Development

HTML output in Production

Client Side

HTML

Razor

  • Precompile cshtml view with RazorGenerator: Nuget package, VS extension . Will help catch errors at compile time and faster
  • Layout : Razor
  • Partial Views : Razor
  • Templating: Underscore templating
  • Less CSS

Javascript Libraries

  • JQuery
  • BackboneJS + UnderscoreJS (Client side framework and tools)
  • Bootstrap (Client side Grid system and default styling)
  • Modernizr (Browser feature detection)
  • Lunr (client side search)
  • Typeahead + Boodhound (autocomplete)
  • momentJS (Everything time related)
  • SignalR (Websockets made easy for realtime communication between client-server)
  • animate.css

Database

  • Locally: Sql Express
  • Production: Sql Server
  • .NET library to manage database tables and relations: Entity Framework, Code First.

Caching

Microsoft Azure

  • Web apps
  • Sql Azure
  • Storage: blob, table, queue
  • CDN
  • Traffic Manager
  • App Insights
  • Media Services
    • Encoding
    • Streaming
    • CDN
    • Media Player
  • VMs
  • Azure KeyVault

Authentication

  • ASP.NET Identity w/ OWIN
  • OAuth
  • External auth using Google and Facebook

CI

Email

  • SendGrid
    • Nuget: SendGrid
    • Azure SendGrid integration: Free 25,000 emails a month

Payments

  • Braintree
    • bower install braintree-web for client side minified javascript
    • Nuget: Braintree for Sever side .NET library
    • Typescript definitions (hmm, Prepared by me)

Security

Testing

.NET code: Xunit

[Fact]
public async Task AddAndGetANewUserTestShouldMatch()
{
 // Arrange    
 user = TestHelpers.CreateUser();  

 // Act       
 user = await this.fixture.UsersRepository.Add(user, "test_user_pass");
 
 // Assert            
 Assert.NotNull(user);
 using (var context = ResoltzDbContext.Create())
 {    
   var actual = context.Users.Find(user.Id); 

   Assert.NotNull(actual);      
   Assert.Equal(user.Id, actual.Id);
   Assert.Equal(user.Email, actual.Email);
   Assert.Equal(user.UserName, actual.UserName);
   Assert.Equal(user.Name, actual.Name);     
 }
}

Javascript: Mocha Chai

describe('Utils', function () {  
 describe('#formatDuration()', function () {
  it('should return 00:00 when the value is less than zero',
     function () {     
   utils.formatDuration(0).should.equal('00:00');
   utils.formatDuration(-1).should.equal('00:00'); 
   utils.formatDuration(-999).should.equal('00:00'); 
  });

  it('should return formatted time when the value is valid', function () {  
    utils.formatDuration(1).should.equal('00:01');     
    utils.formatDuration(60).should.equal('01:00');    
    utils.formatDuration(3599).should.equal('59:59');  
    utils.formatDuration(3600).should.equal('01:00:00');  
    utils.formatDuration(216000).should.equal('60:00:00');  
   });
  });
});
  • CasperJS / PhantomJS: Html & Responsive Design:
  • VS Webtests: Monitoring and acceptance testing:
  • Visual Studio Online: Loading Testing
  • Glimpse: Client Side

Deployment

  • Web Deploy
  • Powershell
  • VIP swap

Monitoring

  • Azure App Insights

Analytics

  • Azure App Insights
  • Mixpanel
  • Google Analytics
  • Facebook Pixel

User Feedback

Tasks and bugs tracking

  • Yammer
  • Asana

Code Analyzers