SlideShare a Scribd company logo
1 of 56
Download to read offline
Alexander Khokhlov
@nots_ioNots.io
ClojureScript journey
From little script,
to CLI program,
to AWS Lambda function
Co-Founder
Nots.io
01
README.md
Code Comments
JavaDoc
GDocs
Confluence / DokuWiki / Wiki system
Nots.io
Add docs for block of code,
function, module, file,
commit or branch
01
Notes, Tied
to Code
Easy to Discover
Easy to Explore
Easy to Get Scope
Easy to Ask and Discuss
01 • Nots.io
We Track
Relevance
You always know what’s fresh
and what’s not.
Promotes keeping docs
up-to-date.
Rewarding when everything is ✅
01 • Nots.io
Discuss with
your Team
You won’t loose a dispute
that is written down.
It’s tied and has context
01 • Nots.io
And many
more
Integration with GitHub
IDE/Editors plugins
Markdown formatting
@mentions
GitHub PR as a Note
Attachments
One-on-one conversations
…
01 • Nots.io
02
https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d
The task:
Detect comment scope
https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d
02 • The task
Analyze!
AST is the best
But tokens are good enough
Tokenizers
ANTLR

Pygments

vscode-textmate
02 • The task
vscode-textmate
02 • The task
https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d
var vsctm = require('vscode-textmate');
var registry = new vsctm.Registry({
loadGrammar: function (scopeName) {
var path = ‘./javascript.tmbundle/Syntaxes/JavaScript.plist';
if (path) {
return new Promise((c, e) => {
fs.readFile(path, (error, content) => {
if (error) { e(error); } else {
var rawGrammar = vsctm.parseRawGrammar(
content.toString(),
path);
c(rawGrammar);
}});});}
return null;
}});
// Load the JavaScript grammar and any other grammars included by it async.
registry.loadGrammar('source.js').then(grammar => {
// at this point `grammar` is available...
var lineTokens = grammar.tokenizeLine(
'function add(a,b) { return a+b; }');
for (var i = 0; i < lineTokens.tokens.length; i++) {
var token = lineTokens.tokens[i];
console.log('Token from ' + token.startIndex +
‘ to ' + token.endIndex);
}
});
Sample
vscode-textmate
02 • The task
https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d
{ tokens:
[ { startIndex: 0,
endIndex: 1,
scopes:
[ 'source.js',
'string.quoted.single.js',
'punctuation.definition.string.begin.js' ],
text: "'",
line: 0 },
{ startIndex: 1,
endIndex: 11,
scopes: [ 'source.js', 'string.quoted.single.js' ],
text: 'use strict',
line: 0 },
{ startIndex: 11,
endIndex: 12,
scopes:
[ 'source.js',
'string.quoted.single.js',
'punctuation.definition.string.end.js' ],
text: "'",
line: 0 },
{ startIndex: 12,
endIndex: 13,
scopes: [ 'source.js', 'punctuation.terminator.statement.js' ],
text: ';',
line: 0 },
Output
Tool which works
great with sequences
02 • The task
🤔
ClojureScript
03
03 • CLJS
LISP
03 • CLJS
LISP
03 • CLJS
Dialect of LISP
Dynamic
Immutable
Persistent
Compiled to JS
Homoiconic
Data-Driven
03 • CLJS
Data-driven
03 • CLJS
Composable
03 • CLJS
98 functions to work
with collections🔥
Isn’t that enough?
03 • CLJS
"It is better to have 100 functions
operate on one data structure than 10
functions on 10 data structures." 

—Alan Perlis
03 • CLJS
All together now
03 • CLJS
Interop
;; Globals
;; alert("Hello!")
(js/alert "Hello!")
;; Function Call
;; "string".toUpperCase()
(.toUpperCase "string")
;; Properties
;; "string".length
(.-length "string")
Interoperability
with JS
03 • CLJS
Interop
;; Chain calls
;; "string".toUpperCase().charCodeAt(1).toString()
(.toString (.charCodeAt (.toUpperCase "string") 1))
(.. "string" (toUpperCase) (charCodeAt 1) (toString))
(.. "string" toUpperCase (charCodeAt 1) toString)
(-> "string" .toUpperCase (.charCodeAt 1) .toString)
;; Chain properties
;; document.body.lastChild.innerHTML.length
(.. js/document -body -lastChild -innerHTML -length)
(-> js/document .-body .-lastChild .-innerHTML .-length)
Interoperability
with JS
03 • CLJS
Interop
(ns myapp)
(defn ^:export func [a]
(str "Hey, " a))
;; in JS:
;; myapp.func("NodeUA!");
How we did it
04
🏗
https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d
Tokenize
04 • How we did it
vscode-textmate
(require '[cljs.build.api :as b])
(b/build "src"
{:main 'notsapp.citation.core
:optimizations :simple
:target :nodejs
:npm-deps {:vscode-textmate “4.1.1”}
:install-deps true
:output-to "notsapp_citation.js"})
04 • How we did it
Get tokens
(ns notsapp.citation.registry
(:require [vscode-textmate :as vstm]
[cljs-node-io.core :as io]
[cljs-node-io.fs :as fs]))
(def reg (new vstm/Registry))
(defn load-all-grammars []
(->> (fs/readdir “grammars")
(filter #(re-find #".json$" %))
(map
#(let [grammar-path (str "grammars/" %)
grammar (io/slurp grammar-path)]
(->> (vstm/parseRawGrammar
grammar grammar-path)
(.addGrammar reg))))))
(defn tokenize-file [file source scope-name]
(when-let [grammar-promise
(.grammarForScopeName reg scope-name)]
(.then grammar-promise
#(.tokenizeLine % source)))))
04 • How we did it
(defn common-block-scopes [input-tokens]
(let [last-idx (-> input-tokens count dec)]
(->>
input-tokens
(keep-indexed
(fn [idx token]
(when (or
(re-find
#"((r)?n){2,}"
(-> token
:text
(str/replace #"[ t]+" "")))
(= idx last-idx))
idx)))
(cons 0)
distinct
(partition 2 1)
(map (fn [[start end]]
(subvec input-tokens (inc start) end))))))
Transform
stream of tokens
04 • How we did it
Transform to CLI
05
📺
05 • Transform to CLI
Transform to CLI
deps.edn
{:deps {org.clojure/clojure {:mvn/version "1.9.0"}
org.clojure/core.async {:mvn/version "0.4.490"}
org.clojure/clojurescript {:mvn/version "1.10.439"}
cljs-node-io {:mvn/version "1.1.2"}
org.clojure/tools.cli {:mvn/version "0.4.1"}
}}
Transform to CLI
clojure.tools.cli
(ns notsapp.citation.core
(:require [cljs.nodejs :as nodejs]
[clojure.tools.cli :as cli]))
(def cli-options
[["-l" "--lang LANG" "Language of a source code file passed via stdin"]
["-s" "--scope LINENUMBER" "Get the scope by given line number"
:parse-fn #(js/parseInt %)]
["-c" "--comments" "Show comments scopes"]
["-h" "--help"]])
(defn -main [& args]
(let [opts (cli/parse-opts args cli-options)
file (-> opts :arguments first)
lang (-> opts :options :lang)
scope-line-number (-> opts :options :scope)
show-comments? (-> opts :options :comments)]
(.exit nodejs/process 0))
(set! *main-cli-fn* -main)
05 • Transform to CLI
Transform to CLI
stdin
(defn read []
(.on
stdin
"readable"
(fn on-readable []
(let [string
(loop [buf (.alloc js/Buffer 0)]
(if-let [data (.read stdin)]
(recur (.concat js/Buffer #js [buf data]))
;else
(.toString buf "utf8")))]
(.removeListener stdin "readable" on-readable)
string))))
05 • Transform to CLI
Transform to CLI
stdout
(ns notsapp.citation.stdout
(:require [clojure.string :as str]
[cljs.nodejs :as nodejs]))
(def stdout (.-stdout nodejs/process))
(defn write [data]
(let [buf (.from js/Buffer data)
data-len (.-length buf)
len-buf (.alloc js/Buffer 4)]
(.writeUInt32BE len-buf data-len 0)
(->> #js [len-buf buf]
(.concat js/Buffer)
(.write stdout))))
05 • Transform to CLI
Compile & exec
> clj build.clj
> node notsapp_citation.js
(require '[cljs.build.api :as b])
(b/build
"src"
{:main 'notsapp.citation.core
:optimizations :simple
:target :nodejs
:npm-deps {:vscode-textmate “4.1.1”}
:install-deps true
:output-to "notsapp_citation.js"})build.clj
05 • Transform to CLI
06
Houston …
06 • AWS Lambda
AWS Lambda
Surprisingly
simple to
transform
; WAS
;(set! *main-cli-fn* -main)
;NOW
(set! (.-exports js/module) #js {:scopelambda scopelambda})
(defn scopelambda [event ctx cb]
(if-let [body (.parse js/JSON (.-body event))]
(cb
nil
#js {:statusCode 200
:headers #js {"Content-Type" "text/plain"}
:body "Hey There!"})
;or else return BAD REQUEST response
(cb
nil
#js {:statusCode 500
:headers #js {"Content-Type" "text/plain"}
:body "Cannot parse request body"})))
06 • AWS Lambda
Compile
build.clj
(require '[cljs.build.api :as b])
(b/build
"src"
{:main 'notsapp.citation.core
:optimizations :simple
:target :nodejs
:npm-deps {:vscode-textmate “4.1.1”}
:install-deps true
:output-to "notsapp_citation.js"})
$ clj build.clj
06 • AWS Lambda
Deploy & exec
$ serverless deploy
serverless.yml
package:
include:
- notsapp_citation.js
- node_modules/**
- grammars/**
exclude:
- src/**
- .git/**
- out/**
functions:
citation:
handler: notsapp_citation.scopelambda
$ serverless invoke -f citation -l
06 • AWS Lambda
07
Testing
07 • Testing
Testing
Entry point
(ns notsapp.citation.core-test
(:require [cljs.test :as t]
[cljs.nodejs :as nodejs]
[notsapp.citation.js-test]))
(nodejs/enable-util-print!)
(defn -main [& args]
(t/run-tests
'notsapp.citation.js-test))
(set! *main-cli-fn* -main)
Testing
The test
(ns notsapp.citation.js-test
(:require [cljs.test
:refer-macros [deftest is]
:as t]))
(t/use-fixtures
:once
{:before load-all-grammars})
(deftest js-scopes-arrow
(is (= (js-scope-arrow-funciton)
[[ 2, 2 ], [ 4, 5 ], [ 7, 8 ]])))
07 • Testing
Testing
Async tests
(deftest js-scopes-arrow
(t/async
done
(->
(tokenize-and-prepare-file
"samples/js/arrow-functions.js")
(.then
(fn [tokens]
(let [scope (js-scope-arrow tokens)]
(is (= scope [[2 2] [4 5] [7 8]])))
(done))))))
07 • Testing
Testing
Build & Execute
> clj build.clj
> node notsapp_tests.js
(require '[cljs.build.api :as b])
(b/build
(b/inputs "test" "src")
{:main 'notsapp.citation.core-test
:optimizations :none
:target :nodejs
:output-to "notsapp_tests.js"
:npm-deps {:vscode-textmate "3.3.3" }
:install-deps true
:output-dir "out_tests"})
07 • Testing
Final thoughts
08
08 • Final thoughts
Pros
Simple, Elegant & Readable
Easy to reason about
Small compassable libraries, not frameworks
Rich collection manipulation functions
FP, immutability, purity, first-class functions
High level data manipulation
CLJ/CLJS code reuse
Macros
Seamless interop with JS/Node.js
Cons
Learning curve, but it’s just an initial hump
Need to study FP
Good to deep dive into CLJ philosophy
Additional JS code added by CLJS itself
Still tangled error messages
Compiled code is hard to read
Need time to fully master the language
Know what you do
08 • Final thoughts
Best Fit
If the task is dedicated
If the team is skilled enough
If you see limit of your current stack
If you’re curious enough
If you want to broaden yours horizons
If you want to be 10x productive
In our opinion
08 • Final thoughts
Thank you
🤘
Alexander Khokhlov
point@nots.io
Nots.io
nots.io
blog.nots.io
@nots_io
facebook.com/nots.io

More Related Content

What's hot

JSLT: JSON querying and transformation
JSLT: JSON querying and transformationJSLT: JSON querying and transformation
JSLT: JSON querying and transformationLars Marius Garshol
 
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015Fernando Hamasaki de Amorim
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Codemotion
 
PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)Nikita Popov
 
POCO C++ Libraries Intro and Overview
POCO C++ Libraries Intro and OverviewPOCO C++ Libraries Intro and Overview
POCO C++ Libraries Intro and OverviewGünter Obiltschnig
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at TwitterAlex Payne
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot CampTroy Miles
 
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing
Cracking JWT tokens: a tale of magic, Node.JS and parallel computingCracking JWT tokens: a tale of magic, Node.JS and parallel computing
Cracking JWT tokens: a tale of magic, Node.JS and parallel computingLuciano Mammino
 
Andrzej Ludwikowski - Event Sourcing - co może pójść nie tak?
Andrzej Ludwikowski -  Event Sourcing - co może pójść nie tak?Andrzej Ludwikowski -  Event Sourcing - co może pójść nie tak?
Andrzej Ludwikowski - Event Sourcing - co może pójść nie tak?SegFaultConf
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Expressjguerrero999
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with JasmineLeon van der Grient
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service ManagerChris Tankersley
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPGuilherme Blanco
 
The state of your own hypertext preprocessor
The state of your own hypertext preprocessorThe state of your own hypertext preprocessor
The state of your own hypertext preprocessorAlessandro Nadalin
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴명신 김
 
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...Lucidworks
 
Introduction to Asynchronous scala
Introduction to Asynchronous scalaIntroduction to Asynchronous scala
Introduction to Asynchronous scalaStratio
 

What's hot (20)

JSLT: JSON querying and transformation
JSLT: JSON querying and transformationJSLT: JSON querying and transformation
JSLT: JSON querying and transformation
 
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
 
PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)PHP 7 – What changed internally? (PHP Barcelona 2015)
PHP 7 – What changed internally? (PHP Barcelona 2015)
 
POCO C++ Libraries Intro and Overview
POCO C++ Libraries Intro and OverviewPOCO C++ Libraries Intro and Overview
POCO C++ Libraries Intro and Overview
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at Twitter
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot Camp
 
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing
Cracking JWT tokens: a tale of magic, Node.JS and parallel computingCracking JWT tokens: a tale of magic, Node.JS and parallel computing
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing
 
Andrzej Ludwikowski - Event Sourcing - co może pójść nie tak?
Andrzej Ludwikowski -  Event Sourcing - co może pójść nie tak?Andrzej Ludwikowski -  Event Sourcing - co może pójść nie tak?
Andrzej Ludwikowski - Event Sourcing - co może pójść nie tak?
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service Manager
 
Scala active record
Scala active recordScala active record
Scala active record
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHP
 
Node.js - Best practices
Node.js  - Best practicesNode.js  - Best practices
Node.js - Best practices
 
The state of your own hypertext preprocessor
The state of your own hypertext preprocessorThe state of your own hypertext preprocessor
The state of your own hypertext preprocessor
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴
 
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...
Distributed Search in Riak - Integrating Search in a NoSQL Database: Presente...
 
Introduction to Asynchronous scala
Introduction to Asynchronous scalaIntroduction to Asynchronous scala
Introduction to Asynchronous scala
 

Similar to "ClojureScript journey: from little script, to CLI program, to AWS Lambda function" Alexander Khokhlov

Shrug2017 arcpy data_and_you
Shrug2017 arcpy data_and_youShrug2017 arcpy data_and_you
Shrug2017 arcpy data_and_youSHRUG GIS
 
Scalding big ADta
Scalding big ADtaScalding big ADta
Scalding big ADtab0ris_1
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.Mike Brevoort
 
Fighting Against Chaotically Separated Values with Embulk
Fighting Against Chaotically Separated Values with EmbulkFighting Against Chaotically Separated Values with Embulk
Fighting Against Chaotically Separated Values with EmbulkSadayuki Furuhashi
 
Mongodb intro
Mongodb introMongodb intro
Mongodb introchristkv
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable CodeBaidu, Inc.
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Web Performance Workshop - Velocity London 2013
Web Performance Workshop - Velocity London 2013Web Performance Workshop - Velocity London 2013
Web Performance Workshop - Velocity London 2013Andy Davies
 
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...NoSQLmatters
 
Shell Tips & Tricks
Shell Tips & TricksShell Tips & Tricks
Shell Tips & TricksMongoDB
 
Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1Mohammad Qureshi
 
.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#Bertrand Le Roy
 
How to create a libcloud driver from scratch
How to create a libcloud driver from scratchHow to create a libcloud driver from scratch
How to create a libcloud driver from scratchMike Muzurakis
 
How to create a libcloud driver from scratch
How to create a libcloud driver from scratchHow to create a libcloud driver from scratch
How to create a libcloud driver from scratchMist.io
 
Microsoft 2014 Dev Plataform - Roslyn -& ASP.NET vNext
Microsoft 2014 Dev Plataform -  Roslyn -& ASP.NET vNextMicrosoft 2014 Dev Plataform -  Roslyn -& ASP.NET vNext
Microsoft 2014 Dev Plataform - Roslyn -& ASP.NET vNextRodolfo Finochietti
 

Similar to "ClojureScript journey: from little script, to CLI program, to AWS Lambda function" Alexander Khokhlov (20)

NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
Shrug2017 arcpy data_and_you
Shrug2017 arcpy data_and_youShrug2017 arcpy data_and_you
Shrug2017 arcpy data_and_you
 
Getting Input from User
Getting Input from UserGetting Input from User
Getting Input from User
 
Unit-2 Getting Input from User.pptx
Unit-2 Getting Input from User.pptxUnit-2 Getting Input from User.pptx
Unit-2 Getting Input from User.pptx
 
Scalding big ADta
Scalding big ADtaScalding big ADta
Scalding big ADta
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.
 
Fighting Against Chaotically Separated Values with Embulk
Fighting Against Chaotically Separated Values with EmbulkFighting Against Chaotically Separated Values with Embulk
Fighting Against Chaotically Separated Values with Embulk
 
Mongodb intro
Mongodb introMongodb intro
Mongodb intro
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable Code
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Web Performance Workshop - Velocity London 2013
Web Performance Workshop - Velocity London 2013Web Performance Workshop - Velocity London 2013
Web Performance Workshop - Velocity London 2013
 
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
 
Shell Tips & Tricks
Shell Tips & TricksShell Tips & Tricks
Shell Tips & Tricks
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Latinoware
LatinowareLatinoware
Latinoware
 
Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1
 
.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#
 
How to create a libcloud driver from scratch
How to create a libcloud driver from scratchHow to create a libcloud driver from scratch
How to create a libcloud driver from scratch
 
How to create a libcloud driver from scratch
How to create a libcloud driver from scratchHow to create a libcloud driver from scratch
How to create a libcloud driver from scratch
 
Microsoft 2014 Dev Plataform - Roslyn -& ASP.NET vNext
Microsoft 2014 Dev Plataform -  Roslyn -& ASP.NET vNextMicrosoft 2014 Dev Plataform -  Roslyn -& ASP.NET vNext
Microsoft 2014 Dev Plataform - Roslyn -& ASP.NET vNext
 

More from Julia Cherniak

"Definition of Done: Deadline driven development" Vitaliy Ratushnyi
"Definition of Done: Deadline driven development" Vitaliy Ratushnyi"Definition of Done: Deadline driven development" Vitaliy Ratushnyi
"Definition of Done: Deadline driven development" Vitaliy RatushnyiJulia Cherniak
 
"Muses Code JS or How Communities Change People" Tanya Butenko
"Muses Code JS or How Communities Change People" Tanya Butenko"Muses Code JS or How Communities Change People" Tanya Butenko
"Muses Code JS or How Communities Change People" Tanya ButenkoJulia Cherniak
 
"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко
"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко
"Принимают за hard skills, увольняют из-за soft skills" Павел ГалушкоJulia Cherniak
 
"It’s about time to embrace Streams" Luciano Mammino
"It’s about time to embrace Streams" Luciano Mammino"It’s about time to embrace Streams" Luciano Mammino
"It’s about time to embrace Streams" Luciano MamminoJulia Cherniak
 
"Node.js and Serverless" Viacheslav Panevskyi
"Node.js and Serverless" Viacheslav Panevskyi"Node.js and Serverless" Viacheslav Panevskyi
"Node.js and Serverless" Viacheslav PanevskyiJulia Cherniak
 
"Lift me up. Mentorship 101" Tanya Butenko
"Lift me up. Mentorship 101" Tanya Butenko"Lift me up. Mentorship 101" Tanya Butenko
"Lift me up. Mentorship 101" Tanya ButenkoJulia Cherniak
 
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D..."Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...Julia Cherniak
 
"Black Clouds and Silver Linings in Node.js Security" Liran Tal
"Black Clouds and Silver Linings in Node.js Security" Liran Tal"Black Clouds and Silver Linings in Node.js Security" Liran Tal
"Black Clouds and Silver Linings in Node.js Security" Liran TalJulia Cherniak
 
"The working architecture of NodeJs applications" Viktor Turskyi
"The working architecture of NodeJs applications" Viktor Turskyi"The working architecture of NodeJs applications" Viktor Turskyi
"The working architecture of NodeJs applications" Viktor TurskyiJulia Cherniak
 
"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren
"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren
"The search for App-iness : Progressive Web Apps" Jamie Maria SchourenJulia Cherniak
 
"The Future of Machine Learning & JavaScript"Asim Hussain
"The Future of Machine Learning & JavaScript"Asim Hussain"The Future of Machine Learning & JavaScript"Asim Hussain
"The Future of Machine Learning & JavaScript"Asim HussainJulia Cherniak
 

More from Julia Cherniak (11)

"Definition of Done: Deadline driven development" Vitaliy Ratushnyi
"Definition of Done: Deadline driven development" Vitaliy Ratushnyi"Definition of Done: Deadline driven development" Vitaliy Ratushnyi
"Definition of Done: Deadline driven development" Vitaliy Ratushnyi
 
"Muses Code JS or How Communities Change People" Tanya Butenko
"Muses Code JS or How Communities Change People" Tanya Butenko"Muses Code JS or How Communities Change People" Tanya Butenko
"Muses Code JS or How Communities Change People" Tanya Butenko
 
"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко
"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко
"Принимают за hard skills, увольняют из-за soft skills" Павел Галушко
 
"It’s about time to embrace Streams" Luciano Mammino
"It’s about time to embrace Streams" Luciano Mammino"It’s about time to embrace Streams" Luciano Mammino
"It’s about time to embrace Streams" Luciano Mammino
 
"Node.js and Serverless" Viacheslav Panevskyi
"Node.js and Serverless" Viacheslav Panevskyi"Node.js and Serverless" Viacheslav Panevskyi
"Node.js and Serverless" Viacheslav Panevskyi
 
"Lift me up. Mentorship 101" Tanya Butenko
"Lift me up. Mentorship 101" Tanya Butenko"Lift me up. Mentorship 101" Tanya Butenko
"Lift me up. Mentorship 101" Tanya Butenko
 
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D..."Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...
"Using Blockchain in Node.js project: JavaScript Ninja’s experience" Maksym D...
 
"Black Clouds and Silver Linings in Node.js Security" Liran Tal
"Black Clouds and Silver Linings in Node.js Security" Liran Tal"Black Clouds and Silver Linings in Node.js Security" Liran Tal
"Black Clouds and Silver Linings in Node.js Security" Liran Tal
 
"The working architecture of NodeJs applications" Viktor Turskyi
"The working architecture of NodeJs applications" Viktor Turskyi"The working architecture of NodeJs applications" Viktor Turskyi
"The working architecture of NodeJs applications" Viktor Turskyi
 
"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren
"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren
"The search for App-iness : Progressive Web Apps" Jamie Maria Schouren
 
"The Future of Machine Learning & JavaScript"Asim Hussain
"The Future of Machine Learning & JavaScript"Asim Hussain"The Future of Machine Learning & JavaScript"Asim Hussain
"The Future of Machine Learning & JavaScript"Asim Hussain
 

Recently uploaded

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationShrmpro
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...Nitya salvi
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsBert Jan Schrijver
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfayushiqss
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 

Recently uploaded (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 

"ClojureScript journey: from little script, to CLI program, to AWS Lambda function" Alexander Khokhlov

  • 1. Alexander Khokhlov @nots_ioNots.io ClojureScript journey From little script, to CLI program, to AWS Lambda function
  • 3.
  • 4.
  • 5.
  • 7. Nots.io Add docs for block of code, function, module, file, commit or branch 01
  • 8. Notes, Tied to Code Easy to Discover Easy to Explore Easy to Get Scope Easy to Ask and Discuss 01 • Nots.io
  • 9. We Track Relevance You always know what’s fresh and what’s not. Promotes keeping docs up-to-date. Rewarding when everything is ✅ 01 • Nots.io
  • 10. Discuss with your Team You won’t loose a dispute that is written down. It’s tied and has context 01 • Nots.io
  • 11. And many more Integration with GitHub IDE/Editors plugins Markdown formatting @mentions GitHub PR as a Note Attachments One-on-one conversations … 01 • Nots.io
  • 15. vscode-textmate 02 • The task https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d var vsctm = require('vscode-textmate'); var registry = new vsctm.Registry({ loadGrammar: function (scopeName) { var path = ‘./javascript.tmbundle/Syntaxes/JavaScript.plist'; if (path) { return new Promise((c, e) => { fs.readFile(path, (error, content) => { if (error) { e(error); } else { var rawGrammar = vsctm.parseRawGrammar( content.toString(), path); c(rawGrammar); }});});} return null; }}); // Load the JavaScript grammar and any other grammars included by it async. registry.loadGrammar('source.js').then(grammar => { // at this point `grammar` is available... var lineTokens = grammar.tokenizeLine( 'function add(a,b) { return a+b; }'); for (var i = 0; i < lineTokens.tokens.length; i++) { var token = lineTokens.tokens[i]; console.log('Token from ' + token.startIndex + ‘ to ' + token.endIndex); } }); Sample
  • 16. vscode-textmate 02 • The task https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d { tokens: [ { startIndex: 0, endIndex: 1, scopes: [ 'source.js', 'string.quoted.single.js', 'punctuation.definition.string.begin.js' ], text: "'", line: 0 }, { startIndex: 1, endIndex: 11, scopes: [ 'source.js', 'string.quoted.single.js' ], text: 'use strict', line: 0 }, { startIndex: 11, endIndex: 12, scopes: [ 'source.js', 'string.quoted.single.js', 'punctuation.definition.string.end.js' ], text: "'", line: 0 }, { startIndex: 12, endIndex: 13, scopes: [ 'source.js', 'punctuation.terminator.statement.js' ], text: ';', line: 0 }, Output
  • 17. Tool which works great with sequences 02 • The task 🤔
  • 21. 03 • CLJS Dialect of LISP Dynamic Immutable Persistent Compiled to JS Homoiconic Data-Driven
  • 24. 03 • CLJS 98 functions to work with collections🔥 Isn’t that enough?
  • 25. 03 • CLJS "It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." 
 —Alan Perlis
  • 26. 03 • CLJS All together now
  • 27. 03 • CLJS Interop ;; Globals ;; alert("Hello!") (js/alert "Hello!") ;; Function Call ;; "string".toUpperCase() (.toUpperCase "string") ;; Properties ;; "string".length (.-length "string") Interoperability with JS
  • 28. 03 • CLJS Interop ;; Chain calls ;; "string".toUpperCase().charCodeAt(1).toString() (.toString (.charCodeAt (.toUpperCase "string") 1)) (.. "string" (toUpperCase) (charCodeAt 1) (toString)) (.. "string" toUpperCase (charCodeAt 1) toString) (-> "string" .toUpperCase (.charCodeAt 1) .toString) ;; Chain properties ;; document.body.lastChild.innerHTML.length (.. js/document -body -lastChild -innerHTML -length) (-> js/document .-body .-lastChild .-innerHTML .-length) Interoperability with JS
  • 29. 03 • CLJS Interop (ns myapp) (defn ^:export func [a] (str "Hey, " a)) ;; in JS: ;; myapp.func("NodeUA!");
  • 30. How we did it 04 🏗
  • 32. vscode-textmate (require '[cljs.build.api :as b]) (b/build "src" {:main 'notsapp.citation.core :optimizations :simple :target :nodejs :npm-deps {:vscode-textmate “4.1.1”} :install-deps true :output-to "notsapp_citation.js"}) 04 • How we did it
  • 33. Get tokens (ns notsapp.citation.registry (:require [vscode-textmate :as vstm] [cljs-node-io.core :as io] [cljs-node-io.fs :as fs])) (def reg (new vstm/Registry)) (defn load-all-grammars [] (->> (fs/readdir “grammars") (filter #(re-find #".json$" %)) (map #(let [grammar-path (str "grammars/" %) grammar (io/slurp grammar-path)] (->> (vstm/parseRawGrammar grammar grammar-path) (.addGrammar reg)))))) (defn tokenize-file [file source scope-name] (when-let [grammar-promise (.grammarForScopeName reg scope-name)] (.then grammar-promise #(.tokenizeLine % source))))) 04 • How we did it
  • 34. (defn common-block-scopes [input-tokens] (let [last-idx (-> input-tokens count dec)] (->> input-tokens (keep-indexed (fn [idx token] (when (or (re-find #"((r)?n){2,}" (-> token :text (str/replace #"[ t]+" ""))) (= idx last-idx)) idx))) (cons 0) distinct (partition 2 1) (map (fn [[start end]] (subvec input-tokens (inc start) end)))))) Transform stream of tokens 04 • How we did it
  • 36. 05 • Transform to CLI Transform to CLI deps.edn {:deps {org.clojure/clojure {:mvn/version "1.9.0"} org.clojure/core.async {:mvn/version "0.4.490"} org.clojure/clojurescript {:mvn/version "1.10.439"} cljs-node-io {:mvn/version "1.1.2"} org.clojure/tools.cli {:mvn/version "0.4.1"} }}
  • 37. Transform to CLI clojure.tools.cli (ns notsapp.citation.core (:require [cljs.nodejs :as nodejs] [clojure.tools.cli :as cli])) (def cli-options [["-l" "--lang LANG" "Language of a source code file passed via stdin"] ["-s" "--scope LINENUMBER" "Get the scope by given line number" :parse-fn #(js/parseInt %)] ["-c" "--comments" "Show comments scopes"] ["-h" "--help"]]) (defn -main [& args] (let [opts (cli/parse-opts args cli-options) file (-> opts :arguments first) lang (-> opts :options :lang) scope-line-number (-> opts :options :scope) show-comments? (-> opts :options :comments)] (.exit nodejs/process 0)) (set! *main-cli-fn* -main) 05 • Transform to CLI
  • 38. Transform to CLI stdin (defn read [] (.on stdin "readable" (fn on-readable [] (let [string (loop [buf (.alloc js/Buffer 0)] (if-let [data (.read stdin)] (recur (.concat js/Buffer #js [buf data])) ;else (.toString buf "utf8")))] (.removeListener stdin "readable" on-readable) string)))) 05 • Transform to CLI
  • 39. Transform to CLI stdout (ns notsapp.citation.stdout (:require [clojure.string :as str] [cljs.nodejs :as nodejs])) (def stdout (.-stdout nodejs/process)) (defn write [data] (let [buf (.from js/Buffer data) data-len (.-length buf) len-buf (.alloc js/Buffer 4)] (.writeUInt32BE len-buf data-len 0) (->> #js [len-buf buf] (.concat js/Buffer) (.write stdout)))) 05 • Transform to CLI
  • 40. Compile & exec > clj build.clj > node notsapp_citation.js (require '[cljs.build.api :as b]) (b/build "src" {:main 'notsapp.citation.core :optimizations :simple :target :nodejs :npm-deps {:vscode-textmate “4.1.1”} :install-deps true :output-to "notsapp_citation.js"})build.clj 05 • Transform to CLI
  • 42. 06 • AWS Lambda AWS Lambda
  • 43. Surprisingly simple to transform ; WAS ;(set! *main-cli-fn* -main) ;NOW (set! (.-exports js/module) #js {:scopelambda scopelambda}) (defn scopelambda [event ctx cb] (if-let [body (.parse js/JSON (.-body event))] (cb nil #js {:statusCode 200 :headers #js {"Content-Type" "text/plain"} :body "Hey There!"}) ;or else return BAD REQUEST response (cb nil #js {:statusCode 500 :headers #js {"Content-Type" "text/plain"} :body "Cannot parse request body"}))) 06 • AWS Lambda
  • 44. Compile build.clj (require '[cljs.build.api :as b]) (b/build "src" {:main 'notsapp.citation.core :optimizations :simple :target :nodejs :npm-deps {:vscode-textmate “4.1.1”} :install-deps true :output-to "notsapp_citation.js"}) $ clj build.clj 06 • AWS Lambda
  • 45. Deploy & exec $ serverless deploy serverless.yml package: include: - notsapp_citation.js - node_modules/** - grammars/** exclude: - src/** - .git/** - out/** functions: citation: handler: notsapp_citation.scopelambda $ serverless invoke -f citation -l 06 • AWS Lambda
  • 47. 07 • Testing Testing Entry point (ns notsapp.citation.core-test (:require [cljs.test :as t] [cljs.nodejs :as nodejs] [notsapp.citation.js-test])) (nodejs/enable-util-print!) (defn -main [& args] (t/run-tests 'notsapp.citation.js-test)) (set! *main-cli-fn* -main)
  • 48. Testing The test (ns notsapp.citation.js-test (:require [cljs.test :refer-macros [deftest is] :as t])) (t/use-fixtures :once {:before load-all-grammars}) (deftest js-scopes-arrow (is (= (js-scope-arrow-funciton) [[ 2, 2 ], [ 4, 5 ], [ 7, 8 ]]))) 07 • Testing
  • 49. Testing Async tests (deftest js-scopes-arrow (t/async done (-> (tokenize-and-prepare-file "samples/js/arrow-functions.js") (.then (fn [tokens] (let [scope (js-scope-arrow tokens)] (is (= scope [[2 2] [4 5] [7 8]]))) (done)))))) 07 • Testing
  • 50. Testing Build & Execute > clj build.clj > node notsapp_tests.js (require '[cljs.build.api :as b]) (b/build (b/inputs "test" "src") {:main 'notsapp.citation.core-test :optimizations :none :target :nodejs :output-to "notsapp_tests.js" :npm-deps {:vscode-textmate "3.3.3" } :install-deps true :output-dir "out_tests"}) 07 • Testing
  • 52. 08 • Final thoughts Pros Simple, Elegant & Readable Easy to reason about Small compassable libraries, not frameworks Rich collection manipulation functions FP, immutability, purity, first-class functions High level data manipulation CLJ/CLJS code reuse Macros Seamless interop with JS/Node.js
  • 53. Cons Learning curve, but it’s just an initial hump Need to study FP Good to deep dive into CLJ philosophy Additional JS code added by CLJS itself Still tangled error messages Compiled code is hard to read Need time to fully master the language Know what you do 08 • Final thoughts
  • 54. Best Fit If the task is dedicated If the team is skilled enough If you see limit of your current stack If you’re curious enough If you want to broaden yours horizons If you want to be 10x productive In our opinion 08 • Final thoughts