Нема описа

Harlan Iverson e310ed6903 removed web-client пре 9 година
clojure-objc-sample ed949232f3 initial import пре 9 година
core ed949232f3 initial import пре 9 година
ios-client ed949232f3 initial import пре 9 година
pubsub-service ed949232f3 initial import пре 9 година
resources ed949232f3 initial import пре 9 година
MIT-LICENSE.txt ed949232f3 initial import пре 9 година
README.md ed949232f3 initial import пре 9 година
project.clj ed949232f3 initial import пре 9 година
project.org ed949232f3 initial import пре 9 година

README.md

Clojure Stack

An industry grade project using clojure everywhere.

To be presented at ForwardJS 4.

Purpose

A baseline Clojure stack that runs on any and all platforms, that is nice to develop and horizontally scalable.

What's here?

  • Leiningen based multi-module project setup with modules for each platform
    • API via bidi with REPL control
    • Web via clojurescript / re-frame
    • iOS via clojure-objc / lein-objcbuild
    • Androd via clojure-android / lein-droid
    • Core via component
  • Integration with Vagrant and Marathon
  • Scalable production deploment configuration
  • Development environment mirroring production environment
  • Jenkins configuration
  • No bullshit (pull request if you disagree)

Philosophy

Claims

  • Continuous Delivery shortens the feedback loop
  • Using a single notation everywhere makes it easy to switch contexts
  • Developing in a production-like environment minimizes surprises
  • Automation is the best process documentation
  • Strong typing need not be obtrusive and static, and is necessary for any evolving system
  • EDN minimally represents all fundamental data structures; the end game of text formats
  • Clojure is easy to read and understand, and is not quite LISP (it's EDN)
  • Investment in Open Source Software leads to better software product outcomes

Choices

Clojure

The fundamental data structures representing code and data; nothing more, nothing less.

  • Same language on and between all platforms
  • core.async channels and CSP concurrency everywhere
  • EDN everywhere, successor to JSON

re-frame

Based on reagent, which using a special atom as the client side sate. Stacks a nice pattern for composable reactive processing of UI actions. Plays well with CQRS and Doman Driven Design.

component

A separation of concerns model for use on all platforms.

We use a custom lifecycle dispatcher that uses multimethods, as suggested by the author's documentation.

(ns my.component
  (:require [clojure.tools.logging :refer [debugf infof]
            [component :refer [react-to] :as c]))
  
(defmulti react)

; namespaced keywords for dispatch
; (when (= *ns* 'my.component) (= ::my-message :my.component/my-message))

(defmethod react :component/start [c]
  (debugf "Starting my.component"))
  
(defmethod react :component/stop [c]
  (debugf "Stopping my.component"))

(defmethod react ::my-message [c msg]
  (infof "Got a message, what are we going to do about it? %s" msg))

; alternative syntax (experimental)
(react-to ::my-message [event]
  (infof "Got a message, what are we going to do about it? %s" msg))

(defmacro defupon
  ""
  [command & body]
  (let [react-symbol (symbol (str *ns*) "upon")
        react-multi `(defmulti ~react-symbol #(:component/event %2))]
    `(do
       (when-not ~(find-var react-symbol)
         (println "Defining default react dispatcher: ")
         ~react-multi) 
       (defmethod ~react-symbol ~command [~'component ~'event]
         ~@body))))


(let [say-reactor '(defupon :say 
                     (format "say with component=%s, event=%s" component event))]
  (println (macroexpand-1 say-reactor))
  (eval say-reactor))

(let [component {:name :my.component}
      event {:component/event :say
             :message "hi"}]
  (upon component event))



(defmacro defaction
  ""
  [command & body]
  `(let [react-symbol# ~(find-var (symbol (str *ns*) "react"))]
     (when-not react-symbol#
       (println "Defining default react dispatcher")
       (defmulti ~'react-symbol# #(:command %2)))
     (defmethod react-symbol# ~command [~'component ~'event]
       ~@body)))


Marathon deployment

Deploy non-Docker packages. Nothing in particular against Docker, but I don't see the case for it with Marathon and debootstrap.

Ansible

familiar with it. yaml basaed DSL. as simple as you want it to be. downside? not edn.

Ubuntu

APT debootstrap

Tool suggestions

IntelliJ Idea with Cursive (free licenses for OSS!)

emacs with clojure-mode and org-mode

homebrew + cask

Thanks

Thanks to all the authors and contributors of the projects used and literature referenced.