Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Rethink Frontend Development With Elm

3,813 views

Published on

Come explore Elm, a functional programming language for making web things. Elm aims to solve some of the same problems that Ember, React, and Angular 2 solve, but in a radically different way. Strong and static typing ensures that data you pass around in your apps really is what you think it is. A simple and tried-and-true architecture makes it easy to understand, and great tooling makes it fun to use.

Published in: Software
  • Be the first to comment

Rethink Frontend Development With Elm

  1. 1. Rethinking Front End Development With Elm Brian Hogan
  2. 2. About me • I build web things. • I teach people. • I make music. • I write books.
  3. 3. Elm is a functional programming language like Haskell, but more friendly, and aimed at front-end web development. We use Elm to make our user interface and give it behavior.
  4. 4. Example import Graphics.Element exposing (show) main = show "Hello World"
  5. 5. Elm compiles to JavaScript Yes. We just wrote a bunch of code that gets injected into an HTML page. Feel gross yet?
  6. 6. That's what React does too. var HelloMessage = React.createClass({ render: function () { return <h1>Hello {this.props.message}!</h1>; } }); React.render(<HelloMessage message="World" />, document.body);
  7. 7. Okay, Why Elm? • Same concepts as React • Pure functions • Immutable State • Static Typing
  8. 8. What you need • Node.js http://nodejs.org • The elm package for Node $ npm install -g elm • Your favorite text editor OR http://elm-lang.org/try
  9. 9. Compiling Elm • Create a hello.elm file • Run $ elm make hello.elm Success! Compiled 1 modules. Successfully generated index.html • Open resulting index.html in your browser.
  10. 10. HTML
  11. 11. Comparison • Elm: ~5400 lines • React: ~19300 lines • JQuery: ~9800 lines
  12. 12. Elm Reactor Elm Reactor compiles Elm to HTML on each request. $ elm-reactor elm reactor 0.16.0 Listening on http://0.0.0.0:8000/
  13. 13. How Elm Works Every Elm app calls a main function when we run it. main = -- something goes here
  14. 14. Functions We define functions with a name followed by an = sign. hello = "Hello there" We indent the definitions of functions. We invoke this function like this: hello
  15. 15. Arguments Functions can have arguments square number = number * number Call it as square 2 They have explicit returns.
  16. 16. Multiple Arguments Multiple arguments use spaces: add number1 number2 = number1 + number2 Call it as add 1 2 Woah.... no commas!
  17. 17. Type annotations We can enforce data types for our functions so Elm can help us out. functionName: TypeOfArg1-> TypeOfArg2 -> TypeOfArg3 -> ReturnType
  18. 18. Annotation Examples: No parameters. Just return value hello: String hello = "Hello there" Two parameters and a return value add: Float -> Float -> Float add number1 number2 = number1 + number2
  19. 19. Modules Define modules to group your code. module Hello where main = -- something goes here
  20. 20. Html functions The elm-html module exposes many functions for building up virtual DOM nodes. The main function can render HTML if the HTML module is included. import Html exposing(p, text) main = p [] [text "Hello World"]
  21. 21. p and text p [] [text "Hello World"] p and text are two functions from elm-html p takes two lists • a list of attributes (can be empty) • a list of child elements text takes a string of text to display.
  22. 22. HTML functions are uniform. Each takes attributes and elements. So we can nest them like HTML. div [class "foo", id "bar" ] [ h1 [] [text "Hello"], p [] [text "World"] ] There's a function for every element. Just be sure to expose what you use.
  23. 23. Seriously uniform label [for "name"] [text "Name"] input [id "name", type' "number", step "any"] [] Even functions for tags that don't allow inner content still take two lists as arguments.
  24. 24. Html Modules • Html contains all the tags • Html.Attributes contains the attributes (like class, id, href, etc) • Html.Events contains events like onClick
  25. 25. Html Attributes import Html exposing(Html, div, text, p) import Html.Attributes exposing(class) main = div [class "wrapper"] [ p [class "notice"] [text "This is important!"] ]
  26. 26. Composability main = view view: Html view = div [] [ p [] [ text "Hello ", em [] [text "world"] ] ]
  27. 27. Resuability main = div [] [ view "Hello", view "Goodbye" ] view: String -> Html view word = div [] [ p [] [ text (word ++ " "), em [] [text "world"] ] ]
  28. 28. Web Interfaces import Html exposing(Html, Attribute, p, text) import Html.Attributes exposing(style) elementStyle: Attribute elementStyle = style [ ("color", "red") , ("font-size", "2em") ] main: Html main = view view = p [elementStyle] [text "Hello World"]
  29. 29. Helpers! fieldWithLabel: String -> String -> String -> Html fieldWithLabel fieldID fieldName fieldType = div [] [ label [for fieldID] [text fieldName], input [ id fieldID, type' fieldType] [] ]
  30. 30. Build Out The Helpers numberField: String -> String -> Html numberField fieldID fieldName = fieldWithLabel fieldID fieldName "number" textField: String -> String -> Html textField fieldID fieldName = fieldWithLabel fieldID fieldName "text" emailField: String -> String -> Html emailField fieldID fieldName = fieldWithLabel fieldID fieldName "email"
  31. 31. Shiny Happy Frontend Code main: Html main = div [] [ textField "name" "Name", numberField "age" "Age", emailField "email" "Email" ]
  32. 32. Elm Architecture View: Function that fires when model changes. Transofms a model into the UI that people see. Model: Something that holds the current state of the app. No behavior. Just the state. No behavior. This is not MVC with objects! Update: Function that fires when state changes. Always returns a new model.
  33. 33. Signals and Mailboxes Signals Signals route messages around the application. Pressing a button is a signal. We can send data along signals. Mailboxes Mailboxes receive signals and send signals. A mailbox has an address and a signal to respond to.
  34. 34. Basic Flow • Model is initialized • View is displayed with model • Events send Signals to Mailboxes • Mailboxes trigger updates • New model is created • New view is rendered Yikes!
  35. 35. Elm StartApp.Simple Like Flux, without all the code. • Define Actions • Define a model to represent data • Define a view function • Define an update function that returns a new model.
  36. 36. Change Text On Click import Html exposing (Html, text, h1, p, div, button) import StartApp.Simple as StartApp import Html.Events exposing (onClick) main = StartApp.start {model = "Hello ", view = view, update = update} view address initialText = div [] [ h1 [] [text "Events"], p [] [ text initialText ], button [onClick address "change"] [text "Push me"] ] update action model = "it changed"
  37. 37. Actions Actions get sent to the Update. type Action = Increment | Decrement model = 0 update: Signal.Action -> Int -> Int update action model = case action of Increment -> model + 1 Decrement -> model - 1
  38. 38. Multiple events main = StartApp.start { model = model, view = view, update = update } view: Signal.Address Action -> Int -> Html view address model = div [] [ button [ onClick address Increment ] [ text "Up" ] , span [] [ text (toString model) ] , button [ onClick address Decrement ] [ text "Down" ] ]
  39. 39. Once again... • StartApp renders the view using an initial model state. • Events defined in the view send Actions to Signal Addresses which route to update. • update returns a new version of the model • StartApp causes the view to be rendered whenever model changes.
  40. 40. Calculator Compound Interest Calculator Write a program to compute the value of an investment compounded over time. The program should ask for the starting amount, the number of years to invest, the interest rate, and the number of periods per year to compound.
  41. 41. Project setup Create folder and file to work in $ mkdir calculator && cd calculator $ touch calculator.elm Init the project $ elm package install Install HTML and StartApp dependencies. $ elm package install evancz/elm-html $ elm package install evancz/start-app
  42. 42. Livereloading Make browser reload when we save $ npm install -g elm-live $ elm-live calculator.elm
  43. 43. Steps • Create the basic app • Build the form • Bind form to model and define events • Perform calculations • Display Output
  44. 44. The Basic App import Html exposing (Html, text, h1, p, div, button, label, input) import Html.Attributes exposing ( style, for, id, step, type', value) import StartApp.Simple as StartApp import Html.Events exposing (onClick) main = StartApp.start {model = model, view = view, update = update}
  45. 45. Define a model and update model: Float model = 0 update: String -> Float -> Float update action model = model
  46. 46. Building the form • Use label, input functions • Use number fields • Each field change updates model state • Clicking button calculates new amount
  47. 47. numberField helper numberField: String -> String -> Html numberField fieldID fieldName = div [] [ label [for fieldID] [text fieldName], input [ id fieldID, type' "number", step "any"] [] ]
  48. 48. Style the form labelStyle: Attribute labelStyle = style [ ("width", "200px") , ("padding", "10px") , ("text-align", "right") , ("display", "inline-block") ]
  49. 49. Apply style to field div [] [ label [labelStyle, for fieldID] [text fieldName], input [ id fieldID, type' "number", step "any"] [] ]
  50. 50. Build the View view: Signal.Address String -> Float -> Html view address model = div [] [ h1 [] [text "Calculator"], div [] [ numberField "principal" "Principal", numberField "rate" "Rate", numberField "years" "Periods", numberField "years" "Years" ] button [onClick address "calculate"] [text "Calculate"] ]
  51. 51. Define Our Actions type Action = NoOp | SetPrinciple String | SetPeriods String | SetRate String | SetYears String | Calculate
  52. 52. Define A Model type alias Model = { principle: String , rate: String , years: String , periods: String , newAmount: Float} model: Model model = { principle = "1500.00" , rate = "4.3" , years = "6" , periods = "4" , newAmount = 0 }
  53. 53. Pass address, action, and model data to fields view: Signal.Address Action -> Model -> Html view address model = div [] [ h1 [] [text "Calculator"], div [] [ numberField address SetPrinciple "principle" "Principle" model.principle, numberField address SetRate "rate" "Rate" model.rate, numberField address SetPeriods "periods" "Periods" model.periods, numberField address SetYears "years" "Years" model.years ], button [onClick address Calculate] [text "Click me"],
  54. 54. Add Events To Form using Actions and model data numberField: Signal.Address Action -> (String -> Action) -> String -> String -> String -> Html numberField address action fieldID name fieldValue = div [] [ label [labelStyle, for fieldID] [text name], input [id fieldID, type' "number", step "any", on "input" targetValue (Signal.message address << action ), value fieldValue] [] ]
  55. 55. Update model from form update: Action -> Model -> Model update action model = case action of NoOp -> model SetPrinciple p -> {model | principle = p} SetRate r -> {model | rate = r} SetYears y -> {model | years = y} SetPeriods p -> {model | periods = p} Calculate -> calculateNewAmount model
  56. 56. The program Logic compoundInterest: Float -> Float -> Float -> Float -> Float compoundInterest principle rate periods years = (principle * (1 + (rate / periods ) ) ^ (years * periods) )
  57. 57. Converting Strings To Floats convertToFloat: String -> Float convertToFloat string = case String.toFloat string of Ok n -> n Err _ -> 0.0
  58. 58. Implement CalculateNewAmount calculateNewAmount: Model -> Model calculateNewAmount model = let rate = convertToFloat model.rate / 100 years = convertToFloat model.years principle = convertToFloat model.principle periods = convertToFloat model.periods in {model | newAmount = (compoundInterest principle rate periods years) }
  59. 59. Display the Output output: Model -> Html output model = div [] [ span [] [text "Amount: "], span [] [text (toString model.newAmount) ] ] And add it to the view.
  60. 60. Discuss What are your thoughts? Is this cool? Good? Bad? A terrible idea or the greatest thing ever?
  61. 61. Issues 1. Tons of code to do simple things 2. Integration with external services is complex 3. Must re-learn a lot of things about web development 4. Small community
  62. 62. Benefits 1. Small community 2. Benefits of React with a clear opinionated approach 3. Fantastic error messages 4. Types ensure data integrity and flow
  63. 63. Write code • Elm website: http://elm-lang.org/ • Try Elm http://elm-lang.org/try • Package system: http://package.elm- lang.org/ • Documentation http://elm-lang.org/docs
  64. 64. Where to go next? Book: http://pragprog.com/titles/bhwb Twitter: @bphogan Material: http://bphogan.com/ presentations/elm2016/ Thank you! © Brian Hogan, 2016. Photos from http://pexels.com

×