SlideShare a Scribd company logo
1 of 32
Download to read offline
CONVERTING TO NODE
How I converted a medium sized Rails project to Node.js
BACKGROUND
•

CTO of Ideal Candidate	


•

MVP existed when I joined	


•

Author of Haraka and a few
other Node.js libraries	


•

Background in Perl and
Anti-Spam
THE RAILS APP
•

Unicorn + Thin + Rails	


•

CoffeeScript with Angular.JS	


•

SASS+Compass for stylesheets	


•

HAML for templates	


•

MySQL + MongoDB	


•

Sidekiq for background tasks
WHY?
APP SIZE
•

5700 Lines of Ruby (170 files)	


•

2500 Lines of CoffeeScript (119 files)	


•

3800 Lines of SASS (42 files)	


•

1500 Lines of HAML (100 files)
FINAL GOAL
•

Express + minimal middleware	


•

PostgreSQL hand coded with referential integrity	


•

Jade templates	


•

SCSS for CSS	


•

Javascript + Angular.js frontend
HOW?
It’s all about the information, Marty
RAILS GIVES YOU
•

Routes	


•

Middleware	


•

DB abstraction layer (aka Model)	


•

Views	


•

Controllers	


•

Configuration	


•

Plugins	


•

A directory structure	


•

Unit tests
EXPRESS GIVES YOU
•

Routes	


•

Middleware	


•

That’s it	


•

(This scares a lot of people)
DIRECTORY STRUCTURE
lib
- general JS libraries	

⌞ model - database accessors	

public
- files that get served to the front end	

⌞ assets - files that are considered part of the app	

⌞ javascripts	

⌞ stylesheets	

⌞ images	

routes
- files that provide express routes for HTML	

⌞ api/v1 - files providing REST API endpoints (JSON)	

views
- Jade templates	

app.js
- entry point
RAILS ASSET PIPELINE
•

Rails does a lot for you, but it’s f ’ing confusing	


•

HAML Template Example:	

•

= javascript_include_tag :application	


•

You’d think this adds <script
src=“application.js”>, but no.
RAILS ASSET PIPELINE
•

Easy if you understand it	


•

Too much magic for my liking	


•

But… the overall effect is good. So I copied some
of it.
JADE EQUIVALENT
	

	

each script in javascripts	
script(src=script, type=“text/javascript”)
APP.JS:
var js = find.fileSync(/.(coffee|js)$/, __dirname + 	
	 ‘/public/assets/javascripts/controllers')	
	 .map(function (i) {	
	 	 return i.replace(/^.*/assets/, ‘/assets')	
	 	 	 	 .replace(/.coffee$/, ‘.js')	
	 });	
app.all('*', function (req, res, next) {	
res.locals.javascripts = js;	
next();	
});
SERVING COFFEESCRIPT
// development	
app.use(require('coffee-middleware')({	
src: __dirname + '/public',	
compress: false,	
}));	

!

// Production	
var all_js = coffee_compiler.generate(js, true);	

!

var shasum = crypto.createHash('sha256');	
shasum.update(all_js);	
var js_sha = shasum.digest('hex');	

!

js = ['/assets/javascripts/application-' + js_sha + '.js'];	

!

app.get('/assets/javascripts/application-' + js_sha + '.js', function (req, res) {	
res.type('js');	
res.setHeader('Cache-Control', 'public, max-age=31557600');	
res.end(all_js);	
});
SERVING SCSS
•

Node-sass module serves .scss files	


•

Doesn’t serve up .sass files (weird, huh?)	


!
# mass-convert.bash	
for F in `find . -name *.sass`; do	
O=“${F/.sass/.scss}”	
sass-convert -F sass -T scss “$F” “$O”	
git rm -f “$F”	
git add “$O”	
done
SCSS APP.JS
function compile_css () {	
console.log("Recompiling CSS");	
resources.watchers.forEach(function (w) {	
w.close();	
});	
	
resources.watchers = [];	

!

!
!
!
}

resources.css = sass.renderSync({	
file: __dirname + '/public/assets/stylesheets/application.scss',	
includePaths: [__dirname + '/public/assets/stylesheets'],	
});	
var shasum = crypto.createHash('sha256');	
shasum.update(resources.css);	
var css_sha = shasum.digest('hex');	
resources.stylesheets[0] = '/assets/stylesheets/application-' + css_sha + '.css';	
resources.stylesheets[1] = '//fonts.googleapis.com/css?family=Open+Sans:400,700,800,300,600';	
find.fileSync(cssregexp, __dirname + '/public/assets/stylesheets').forEach(function (f) {	
resources.watchers.push(fs.watch(f, compile_css));	
})
SCSS APP.JS

compile_css();	

!
// Dev and Production the same	
app.get(//assets/stylesheets/application-(w+).css/, function (req, res) {	
res.type('css');	
res.setHeader('Cache-Control', 'public, max-age=31557600');	
res.end(resources.css);	
});
ADDING COMPASS
•

Ruby CSS framework	


•

Luckily only the CSS3 part used	


•

CSS3 code is just SASS files	


•

Once I figured this out, copied them into my
project, et voila!
CONVERTING HAML TO JADE
•

Both indent based	


•

HAML:	


	
	
	
	
	

•
	
	
	

•

	
	
	
	
	

%tag{attr: “Value”}	
	
Some Text	
.person	
	
.name	
	
	
Bob	

JADE:	

	
	
	

tag(attr=“Value”) Some Text	
.person	
	
.name Bob	

Other subtle differences too
CONVERSION TOOL: SUBLIME
TEXT
•

Afterthought: I should have written something in Perl	


•

Regexp Find/Replace	

•

^(s*)%

=> $1 (fix tags)	


•

(w){(.*)} => $1($2) (attribute curlys)	


•

(w):s*([“‘]) => $1=$2 (attribute key: value)
THINGS LEFT TO FIX
•

Helpers: = some_helper	


•

Text on a line on its own - Jade treats these as tags	


•

Nested attributes:	


	
	

•

	
->

%tag{ng:{style:’…’,click:’…’},class:’foo’}	
tag(ng-style=‘…’, ng-click=‘…’, class=‘foo’)	

Making sure the output matched the Ruby/HAML
version was HARD - HTML Diff tools suck
HELPERS BECAME MIXINS
•

Standard Rails Helpers:	


= form_for @person do |f|	
f.label :first_name	
f.text_field :first_name	
%br	

!
f.label :last_name	
f.text_field :last_name	
%br	

!
f.submit	

•

Custom Rails helpers stored in app/helpers/ folder	


•

http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
JADE MIXINS
•

Very powerful. Poorly documented.	


•

Standalone or can have block contents	

// implementation	
mixin form(action)	
form(accept-charset="UTF-8", action=action, method="POST")	
input(name="utf8" type="hidden" value="&#x2713;")	
block	
// usage:	
+form(‘/post/to/here’)	
input(type=“text”,name=“hello”,value=“world”)	

•

Supports js code	

mixin app_error(field)	
if (errors && errors[field])	
div(class="err_msg " + field)	
each error in errors[field]	
span= error
JADE: NO DYNAMIC
INCLUDES
•

HAML/Helpers can do:	


	 	

= popup ‘roles/new'	

•

Jade needed:	


	
	

	
	

+popup(‘roles/new’)	
	
include ../roles/new
CREATING THE MODEL
•

Hand coded db.js layer developed over time from previous
projects	


•

One file per table (generally) in lib/model/*.js	


	
	
	
	
	

"use strict";	
	
var db = require('./db');	
	
exports.get = function get (id, cb) {	
	
	
db.get_one_row("SELECT * FROM Answers WHERE id=$1", [id], cb);	
}	
	
exports.get_by_submission_id = function (submission_id, cb) {	
	
	
db.query("SELECT * FROM Answers	
	
WHERE submission_id=$1	
	
	
ORDER BY question_id", [submission_id], cb);	
}
WHY CONTROL THE SQL?
exports.get_avg_team_size = function (company_id, role_id, months, cb) {	
var role_sql = role_id ? ' AND role_id=$2' : ' AND $2=$2';	

!
!

}	

if (months == 0 || months == '0') {	
months = '9000'; // OVER NINE THOUSAND	
}	
var sql = "SELECT avg(c) as value	
FROM (	
SELECT g.month, count(e.*)	
FROM generate_series(	
date_trunc('month', now() - CAST($3 AS INTERVAL)),	
now(),	
INTERVAL '1 month') g(month)	
LEFT JOIN employees e ON e.company_id=$1" + role_sql + "	
AND (start_date, COALESCE(end_date, 'infinity'))	
OVERLAPS	
(g.month, INTERVAL '1 month')	
GROUP BY g.month	
HAVING count(e.*) > 0	
) av(month,c)";	
db.get_one_row(sql, [company_id, role_id, months + " months"], cb);
AND FINALLY…
•

Routes	

•

Run Rails version of App	


•

Open Chrome Dev Console Network tools	


•

Hit record	


•

Find all routes and implement them
CREATING ROUTES/MODELS
•

While I glossed over this, it was the bulk of the
work	


•

Each endpoint was painstakingly re-created	


•

This allowed me to get a view of the DB layout	

•

And fix design bugs in the DB layout

find.fileSync(/.js$/, __dirname + '/routes').forEach(function (route_file) {	
require(route_file);	
});
BACKGROUND TASKS
•

Currently using Sidekiq, which uses Redis as a queue	

•

Used for downloading slow data feeds	


•

Node.js doesn’t care if downloads are slow	


•

So I punted on background tasks for now	


•

If I need them later I will use Kue (see npmjs.org)
DEPLOYMENT
•

Linode + Nginx + Postgres 9.3.1 + Runit +
Memcached	


•

/var/apps and deploy_to_runit for github autodeploy	


•

Monitoring via Zabbix	


•

60M used vs 130M for Rails
NEXT STEPS
•

Convert coffeescript code to plain JS - I find
coffeescript too much of a pain	


•

Implement graceful restarts using cluster	


•

Consider porting CSS to Bootstrap so we get
mobile support

More Related Content

What's hot

Gas leakage detection system
Gas leakage detection systemGas leakage detection system
Gas leakage detection systemAashiq Ahamed N
 
BRAIN COMPUTER INTERFACE......
BRAIN COMPUTER INTERFACE......BRAIN COMPUTER INTERFACE......
BRAIN COMPUTER INTERFACE......AGGARWAL0522
 
Neuralink technical seminar
Neuralink technical seminarNeuralink technical seminar
Neuralink technical seminarRahul Agarwal
 
Seminar Neuro-computing
Seminar Neuro-computingSeminar Neuro-computing
Seminar Neuro-computingAniket Jadhao
 
Smart door project ppt shivnaresh likhar
Smart door project ppt shivnaresh likharSmart door project ppt shivnaresh likhar
Smart door project ppt shivnaresh likharShivnaresh Likhar
 
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNO
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNOALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNO
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNOIRJET Journal
 
Brain computer interface
Brain computer interfaceBrain computer interface
Brain computer interfaceSharat045
 
Brain computer interface
Brain computer interfaceBrain computer interface
Brain computer interfaceKomal Maloo
 
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEM
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEMAUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEM
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEMAnamika Vinod
 
Street Light that Glows on Detecting Vehicle Movement
Street Light that Glows on Detecting Vehicle MovementStreet Light that Glows on Detecting Vehicle Movement
Street Light that Glows on Detecting Vehicle MovementEdgefxkits & Solutions
 
Gas sensor Alarm
Gas sensor AlarmGas sensor Alarm
Gas sensor AlarmUdit Jain
 
Biochip seminar ppt 2014
Biochip seminar ppt 2014Biochip seminar ppt 2014
Biochip seminar ppt 2014Mrinal Sharma
 
WIRELWIRELESS INTEGRATED NETWORK SENSORS
WIRELWIRELESS INTEGRATED NETWORK SENSORSWIRELWIRELESS INTEGRATED NETWORK SENSORS
WIRELWIRELESS INTEGRATED NETWORK SENSORSDeepak Kumar Mohapatra
 
Digital jewellery final report
Digital jewellery final reportDigital jewellery final report
Digital jewellery final reportDuggirala Madhu
 

What's hot (20)

Gas leakage detection system
Gas leakage detection systemGas leakage detection system
Gas leakage detection system
 
BRAIN COMPUTER INTERFACE......
BRAIN COMPUTER INTERFACE......BRAIN COMPUTER INTERFACE......
BRAIN COMPUTER INTERFACE......
 
Neuralink technical seminar
Neuralink technical seminarNeuralink technical seminar
Neuralink technical seminar
 
Seminar Neuro-computing
Seminar Neuro-computingSeminar Neuro-computing
Seminar Neuro-computing
 
Smart door project ppt shivnaresh likhar
Smart door project ppt shivnaresh likharSmart door project ppt shivnaresh likhar
Smart door project ppt shivnaresh likhar
 
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNO
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNOALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNO
ALCOHOL DETECTION AND ENGINE LOCKING SYSTEM USING ARDUINO UNO
 
Seminar
SeminarSeminar
Seminar
 
Brain computer interface
Brain computer interfaceBrain computer interface
Brain computer interface
 
Brain computer interface
Brain computer interfaceBrain computer interface
Brain computer interface
 
Neuralink
NeuralinkNeuralink
Neuralink
 
Brain computer interface
Brain computer interfaceBrain computer interface
Brain computer interface
 
Biochip
BiochipBiochip
Biochip
 
Neuralink white-paper. Elon Musk & Neuralink
Neuralink white-paper. Elon Musk & NeuralinkNeuralink white-paper. Elon Musk & Neuralink
Neuralink white-paper. Elon Musk & Neuralink
 
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEM
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEMAUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEM
AUTOMATIC ACCIDENT DETECTION AND ALERT SYSTEM
 
Street Light that Glows on Detecting Vehicle Movement
Street Light that Glows on Detecting Vehicle MovementStreet Light that Glows on Detecting Vehicle Movement
Street Light that Glows on Detecting Vehicle Movement
 
Gas sensor Alarm
Gas sensor AlarmGas sensor Alarm
Gas sensor Alarm
 
Biochip seminar ppt 2014
Biochip seminar ppt 2014Biochip seminar ppt 2014
Biochip seminar ppt 2014
 
Electronic skin
Electronic skinElectronic skin
Electronic skin
 
WIRELWIRELESS INTEGRATED NETWORK SENSORS
WIRELWIRELESS INTEGRATED NETWORK SENSORSWIRELWIRELESS INTEGRATED NETWORK SENSORS
WIRELWIRELESS INTEGRATED NETWORK SENSORS
 
Digital jewellery final report
Digital jewellery final reportDigital jewellery final report
Digital jewellery final report
 

Similar to Converting a Rails application to Node.js

Intro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneIntro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneMarius Soutier
 
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology Ayes Chinmay
 
前端MVC之BackboneJS
前端MVC之BackboneJS前端MVC之BackboneJS
前端MVC之BackboneJSZhang Xiaoxue
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJSAaronius
 
Amazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersAmazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersJeremy Lindblom
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...Amazon Web Services
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Solutions for bi-directional Integration between Oracle RDMBS & Apache Kafka
Solutions for bi-directional Integration between Oracle RDMBS & Apache KafkaSolutions for bi-directional Integration between Oracle RDMBS & Apache Kafka
Solutions for bi-directional Integration between Oracle RDMBS & Apache KafkaGuido Schmutz
 
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...confluent
 
3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developersChristopher Batey
 
Manchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationManchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationChristopher Batey
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLAll Things Open
 
Intro to Spark and Spark SQL
Intro to Spark and Spark SQLIntro to Spark and Spark SQL
Intro to Spark and Spark SQLjeykottalam
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaKazuhiro Sera
 
Reading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkReading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkChristopher Batey
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 

Similar to Converting a Rails application to Node.js (20)

Intro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG CologneIntro to Scala.js - Scala UG Cologne
Intro to Scala.js - Scala UG Cologne
 
Couchbas for dummies
Couchbas for dummiesCouchbas for dummies
Couchbas for dummies
 
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology
Internet and Web Technology (CLASS-10) [Node.js] | NIC/NIELIT Web Technology
 
前端MVC之BackboneJS
前端MVC之BackboneJS前端MVC之BackboneJS
前端MVC之BackboneJS
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
Amazon Web Services for PHP Developers
Amazon Web Services for PHP DevelopersAmazon Web Services for PHP Developers
Amazon Web Services for PHP Developers
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Solutions for bi-directional Integration between Oracle RDMBS & Apache Kafka
Solutions for bi-directional Integration between Oracle RDMBS & Apache KafkaSolutions for bi-directional Integration between Oracle RDMBS & Apache Kafka
Solutions for bi-directional Integration between Oracle RDMBS & Apache Kafka
 
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...
Solutions for bi-directional integration between Oracle RDBMS and Apache Kafk...
 
3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers
 
Manchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationManchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra Integration
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQL
 
Intro to Spark and Spark SQL
Intro to Spark and Spark SQLIntro to Spark and Spark SQL
Intro to Spark and Spark SQL
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in Scala
 
Reading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkReading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache Spark
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 

Recently uploaded

How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfSrushith Repakula
 
ECS 2024 Teams Premium - Pretty Secure
ECS 2024   Teams Premium - Pretty SecureECS 2024   Teams Premium - Pretty Secure
ECS 2024 Teams Premium - Pretty SecureFemke de Vroome
 
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...marcuskenyatta275
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceSamy Fodil
 
Syngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdfSyngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdfSyngulon
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...FIDO Alliance
 
PLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. StartupsPLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. StartupsStefano
 
Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024Enterprise Knowledge
 
Google I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGoogle I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGDSC PJATK
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessUXDXConf
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...panagenda
 
Using IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandUsing IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandIES VE
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform EngineeringMarcus Vechiato
 
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptx
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptxBT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptx
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptxNeo4j
 
Powerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaPowerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaCzechDreamin
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfUK Journal
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераMark Opanasiuk
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPTiSEO AI
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireExakis Nelite
 

Recently uploaded (20)

How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
ECS 2024 Teams Premium - Pretty Secure
ECS 2024   Teams Premium - Pretty SecureECS 2024   Teams Premium - Pretty Secure
ECS 2024 Teams Premium - Pretty Secure
 
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Syngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdfSyngulon - Selection technology May 2024.pdf
Syngulon - Selection technology May 2024.pdf
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
 
PLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. StartupsPLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. Startups
 
Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024Enterprise Knowledge Graphs - Data Summit 2024
Enterprise Knowledge Graphs - Data Summit 2024
 
Google I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGoogle I/O Extended 2024 Warsaw
Google I/O Extended 2024 Warsaw
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
 
Using IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandUsing IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & Ireland
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptx
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptxBT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptx
BT & Neo4j _ How Knowledge Graphs help BT deliver Digital Transformation.pptx
 
Powerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaPowerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara Laskowska
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - Questionnaire
 
Overview of Hyperledger Foundation
Overview of Hyperledger FoundationOverview of Hyperledger Foundation
Overview of Hyperledger Foundation
 

Converting a Rails application to Node.js

  • 1. CONVERTING TO NODE How I converted a medium sized Rails project to Node.js
  • 2. BACKGROUND • CTO of Ideal Candidate • MVP existed when I joined • Author of Haraka and a few other Node.js libraries • Background in Perl and Anti-Spam
  • 3. THE RAILS APP • Unicorn + Thin + Rails • CoffeeScript with Angular.JS • SASS+Compass for stylesheets • HAML for templates • MySQL + MongoDB • Sidekiq for background tasks
  • 5. APP SIZE • 5700 Lines of Ruby (170 files) • 2500 Lines of CoffeeScript (119 files) • 3800 Lines of SASS (42 files) • 1500 Lines of HAML (100 files)
  • 6. FINAL GOAL • Express + minimal middleware • PostgreSQL hand coded with referential integrity • Jade templates • SCSS for CSS • Javascript + Angular.js frontend
  • 7. HOW? It’s all about the information, Marty
  • 8. RAILS GIVES YOU • Routes • Middleware • DB abstraction layer (aka Model) • Views • Controllers • Configuration • Plugins • A directory structure • Unit tests
  • 9. EXPRESS GIVES YOU • Routes • Middleware • That’s it • (This scares a lot of people)
  • 10. DIRECTORY STRUCTURE lib - general JS libraries ⌞ model - database accessors public - files that get served to the front end ⌞ assets - files that are considered part of the app ⌞ javascripts ⌞ stylesheets ⌞ images routes - files that provide express routes for HTML ⌞ api/v1 - files providing REST API endpoints (JSON) views - Jade templates app.js - entry point
  • 11. RAILS ASSET PIPELINE • Rails does a lot for you, but it’s f ’ing confusing • HAML Template Example: • = javascript_include_tag :application • You’d think this adds <script src=“application.js”>, but no.
  • 12. RAILS ASSET PIPELINE • Easy if you understand it • Too much magic for my liking • But… the overall effect is good. So I copied some of it.
  • 13. JADE EQUIVALENT each script in javascripts script(src=script, type=“text/javascript”)
  • 14. APP.JS: var js = find.fileSync(/.(coffee|js)$/, __dirname + ‘/public/assets/javascripts/controllers') .map(function (i) { return i.replace(/^.*/assets/, ‘/assets') .replace(/.coffee$/, ‘.js') }); app.all('*', function (req, res, next) { res.locals.javascripts = js; next(); });
  • 15. SERVING COFFEESCRIPT // development app.use(require('coffee-middleware')({ src: __dirname + '/public', compress: false, })); ! // Production var all_js = coffee_compiler.generate(js, true); ! var shasum = crypto.createHash('sha256'); shasum.update(all_js); var js_sha = shasum.digest('hex'); ! js = ['/assets/javascripts/application-' + js_sha + '.js']; ! app.get('/assets/javascripts/application-' + js_sha + '.js', function (req, res) { res.type('js'); res.setHeader('Cache-Control', 'public, max-age=31557600'); res.end(all_js); });
  • 16. SERVING SCSS • Node-sass module serves .scss files • Doesn’t serve up .sass files (weird, huh?) ! # mass-convert.bash for F in `find . -name *.sass`; do O=“${F/.sass/.scss}” sass-convert -F sass -T scss “$F” “$O” git rm -f “$F” git add “$O” done
  • 17. SCSS APP.JS function compile_css () { console.log("Recompiling CSS"); resources.watchers.forEach(function (w) { w.close(); }); resources.watchers = []; ! ! ! ! } resources.css = sass.renderSync({ file: __dirname + '/public/assets/stylesheets/application.scss', includePaths: [__dirname + '/public/assets/stylesheets'], }); var shasum = crypto.createHash('sha256'); shasum.update(resources.css); var css_sha = shasum.digest('hex'); resources.stylesheets[0] = '/assets/stylesheets/application-' + css_sha + '.css'; resources.stylesheets[1] = '//fonts.googleapis.com/css?family=Open+Sans:400,700,800,300,600'; find.fileSync(cssregexp, __dirname + '/public/assets/stylesheets').forEach(function (f) { resources.watchers.push(fs.watch(f, compile_css)); })
  • 18. SCSS APP.JS compile_css(); ! // Dev and Production the same app.get(//assets/stylesheets/application-(w+).css/, function (req, res) { res.type('css'); res.setHeader('Cache-Control', 'public, max-age=31557600'); res.end(resources.css); });
  • 19. ADDING COMPASS • Ruby CSS framework • Luckily only the CSS3 part used • CSS3 code is just SASS files • Once I figured this out, copied them into my project, et voila!
  • 20. CONVERTING HAML TO JADE • Both indent based • HAML: • • %tag{attr: “Value”} Some Text .person .name Bob JADE: tag(attr=“Value”) Some Text .person .name Bob Other subtle differences too
  • 21. CONVERSION TOOL: SUBLIME TEXT • Afterthought: I should have written something in Perl • Regexp Find/Replace • ^(s*)% => $1 (fix tags) • (w){(.*)} => $1($2) (attribute curlys) • (w):s*([“‘]) => $1=$2 (attribute key: value)
  • 22. THINGS LEFT TO FIX • Helpers: = some_helper • Text on a line on its own - Jade treats these as tags • Nested attributes: • -> %tag{ng:{style:’…’,click:’…’},class:’foo’} tag(ng-style=‘…’, ng-click=‘…’, class=‘foo’) Making sure the output matched the Ruby/HAML version was HARD - HTML Diff tools suck
  • 23. HELPERS BECAME MIXINS • Standard Rails Helpers: = form_for @person do |f| f.label :first_name f.text_field :first_name %br ! f.label :last_name f.text_field :last_name %br ! f.submit • Custom Rails helpers stored in app/helpers/ folder • http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
  • 24. JADE MIXINS • Very powerful. Poorly documented. • Standalone or can have block contents // implementation mixin form(action) form(accept-charset="UTF-8", action=action, method="POST") input(name="utf8" type="hidden" value="&#x2713;") block // usage: +form(‘/post/to/here’) input(type=“text”,name=“hello”,value=“world”) • Supports js code mixin app_error(field) if (errors && errors[field]) div(class="err_msg " + field) each error in errors[field] span= error
  • 25. JADE: NO DYNAMIC INCLUDES • HAML/Helpers can do: = popup ‘roles/new' • Jade needed: +popup(‘roles/new’) include ../roles/new
  • 26. CREATING THE MODEL • Hand coded db.js layer developed over time from previous projects • One file per table (generally) in lib/model/*.js "use strict"; var db = require('./db'); exports.get = function get (id, cb) { db.get_one_row("SELECT * FROM Answers WHERE id=$1", [id], cb); } exports.get_by_submission_id = function (submission_id, cb) { db.query("SELECT * FROM Answers WHERE submission_id=$1 ORDER BY question_id", [submission_id], cb); }
  • 27. WHY CONTROL THE SQL? exports.get_avg_team_size = function (company_id, role_id, months, cb) { var role_sql = role_id ? ' AND role_id=$2' : ' AND $2=$2'; ! ! } if (months == 0 || months == '0') { months = '9000'; // OVER NINE THOUSAND } var sql = "SELECT avg(c) as value FROM ( SELECT g.month, count(e.*) FROM generate_series( date_trunc('month', now() - CAST($3 AS INTERVAL)), now(), INTERVAL '1 month') g(month) LEFT JOIN employees e ON e.company_id=$1" + role_sql + " AND (start_date, COALESCE(end_date, 'infinity')) OVERLAPS (g.month, INTERVAL '1 month') GROUP BY g.month HAVING count(e.*) > 0 ) av(month,c)"; db.get_one_row(sql, [company_id, role_id, months + " months"], cb);
  • 28. AND FINALLY… • Routes • Run Rails version of App • Open Chrome Dev Console Network tools • Hit record • Find all routes and implement them
  • 29. CREATING ROUTES/MODELS • While I glossed over this, it was the bulk of the work • Each endpoint was painstakingly re-created • This allowed me to get a view of the DB layout • And fix design bugs in the DB layout find.fileSync(/.js$/, __dirname + '/routes').forEach(function (route_file) { require(route_file); });
  • 30. BACKGROUND TASKS • Currently using Sidekiq, which uses Redis as a queue • Used for downloading slow data feeds • Node.js doesn’t care if downloads are slow • So I punted on background tasks for now • If I need them later I will use Kue (see npmjs.org)
  • 31. DEPLOYMENT • Linode + Nginx + Postgres 9.3.1 + Runit + Memcached • /var/apps and deploy_to_runit for github autodeploy • Monitoring via Zabbix • 60M used vs 130M for Rails
  • 32. NEXT STEPS • Convert coffeescript code to plain JS - I find coffeescript too much of a pain • Implement graceful restarts using cluster • Consider porting CSS to Bootstrap so we get mobile support

Editor's Notes

  1. Knowledge Hiring Lack of “Magic” Performance Queryability PostgreSQL Referential integrity Pre-Customers so zero downtime
  2. “Little ones and zeros, it’s all just electrons”. Web apps are a flow of information. HTML+JS goes to the client, XHR queries come back, XHR responses get sent, POST and PUT requests modify data. Monitor all these, watch the flow, and you have your app. The backend is unimportant at that level.
  3. And probably more
  4. Let’s start with a solid directory structure. I always do this when I’m creating express apps as it helps me stay grounded and not create too many hacks. My app.js has evolved a bit over time to include many things. Happy to share it.
  5. What it actually does: Looks for your application.js. If it doesn’t find it, looks for application.coffee. It then scans that file for comments containing =require or =require_tree In production it loads all those files, coffee script compiles them if necessary, minimises, and delivers via a &lt;script src=“application-$md5.js”&gt;. In dev, it puts in as many &lt;script&gt; tags as required for each file and delivers them, coffee script compiled. Rails does the same for SASS stylesheets. FML.
  6. I wrote coffee_compiler - but it’s very simple
  7. Did this by installing the gem, finding the .sass files, and copying them over to my project.
  8. Helpers are functions to simplify HTML generation. Rails comes with a bunch that help with creating forms (and some others). These had to be ported to become Jade mixins.
  9. HAML version creates some HTML and loads the template ‘views/roles/new’ to be part of the content Jade cannot do that, so we manually include the template
  10. Slightly more code than ActiveRecord, but gives you full control over SQL Only returns plain objects, doesn’t support dynamic updates Considering using getters/setters for next iteration, but not sure how they serialize