Commit 2b373dc2 authored by Allele Dev's avatar Allele Dev

docs: add slides for workshop

parent d788eb8a
.stack-work .stack-work
dist dist
dump.rdb dump.rdb
*.pdf
*.log
*.tex
*.out
*.aux
#!/usr/bin/env bash
echo `which pandoc`
if ! [ -x `which pandoc` ]
then
echo "Install pandoc; cabal install pandoc"
exit
fi
echo "Build talk.pdf"
pandoc -t beamer -V theme:Warsaw --template=my.beamer slides.md -o talk.pdf
echo "talk.pdf available"
\documentclass[$if(fontsize)$$fontsize$,$endif$$if(handout)$handout,$endif$$if(beamer)$ignorenonframetext,$endif$]{$documentclass$}
\definecolor{links}{HTML}{811B2A}
\hypersetup{colorlinks,linkcolor=,urlcolor=links}
$if(theme)$
\usetheme{$theme$}
$endif$
$if(colortheme)$
\usecolortheme{$colortheme$}
$endif$
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\ifxetex
\usepackage{fontspec,xltxtra,xunicode}
\defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase}
\else
\ifluatex
\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase}
\else
\usepackage[utf8]{inputenc}
\fi
\fi
$if(natbib)$
\usepackage{natbib}
\bibliographystyle{plainnat}
$endif$
$if(biblatex)$
\usepackage{biblatex}
$if(biblio-files)$
\bibliography{$biblio-files$}
$endif$
$endif$
$if(listings)$
\usepackage{listings}
$endif$
$if(lhs)$
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
$endif$
$if(highlighting-macros)$
$highlighting-macros$
$endif$
$if(verbatim-in-note)$
\usepackage{fancyvrb}
$endif$
$if(fancy-enums)$
% Redefine labelwidth for lists; otherwise, the enumerate package will cause
% markers to extend beyond the left margin.
\makeatletter\AtBeginDocument{%
\renewcommand{\@listi}
{\setlength{\labelwidth}{4em}}
}\makeatother
\usepackage{enumerate}
$endif$
$if(tables)$
\usepackage{ctable}
\usepackage{float} % provides the H option for float placement
$endif$
$if(url)$
\usepackage{url}
$endif$
$if(graphics)$
\usepackage{graphicx}
$endif$
% Comment these out if you don't want a slide with just the
% part/section/subsection/subsubsection title:
\AtBeginPart{\frame{\partpage}}
\AtBeginSection{\frame{\sectionpage}}
\AtBeginSubsection{\frame{\subsectionpage}}
\AtBeginSubsubsection{\frame{\subsubsectionpage}}
$if(strikeout)$
\usepackage[normalem]{ulem}
% avoid problems with \sout in headers with hyperref:
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
$endif$
$if(subscript)$
\newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
$endif$
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
\setlength{\emergencystretch}{3em} % prevent overfull lines
$if(numbersections)$
$else$
\setcounter{secnumdepth}{0}
$endif$
$if(verbatim-in-note)$
\VerbatimFootnotes % allows verbatim text in footnotes
$endif$
$if(lang)$
\usepackage[$lang$]{babel}
$endif$
$for(header-includes)$
$header-includes$
$endfor$
$if(title)$
\title{$title$}
$endif$
$if(author)$
\author{$for(author)$$author$$sep$ \and $endfor$}
$endif$
$if(date)$
\date{$date$}
$endif$
\def\tightlist{}
\begin{document}
$if(title)$
\frame{\titlepage}
$endif$
$for(include-before)$
$include-before$
$endfor$
$if(toc)$
\begin{frame}
\tableofcontents[hideallsubsections]
\end{frame}
$endif$
$body$
$if(natbib)$
$if(biblio-files)$
$if(biblio-title)$
$if(book-class)$
\renewcommand\bibname{$biblio-title$}
$else$
\renewcommand\refname{$biblio-title$}
$endif$
$endif$
\bibliography{$biblio-files$}
$endif$
$endif$
$if(biblatex)$
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
$endif$
$for(include-after)$
$include-after$
$endfor$
\end{document}
% Haskell Web Services
% Alej C. (@queertypes)
% September 24, 2015
# Finding Me
* Gitlab: [homepage](https://gitlab.com/u/cpp.cabrera)
* Twitter: @[queertypes](https://twitter.com/queertypes)
* Slack: queertypes
* Blog: [homepage](https://blog.cppcabrera.com/)
# Haskell
> * A "purely" functional language
> * That is to say, it tracks effects for you
> * Immutability is the default and easy
> * Mutability is possible
> * It's been around since about 1987
> * The [history](http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/) is a fun read
> * It gets easier and nicer to use over time
> * Package manager: cabal
> * Package manager, easy-mode: stack
> * Editor support: emacs, vim, atom, sublime
> * Lots of libraries for many things
> * It's pretty fun, too
# Web Services
> * Very loosely defined thing that's exposed to the internet
> * For this workshop:
> * Built on top of HTTP
> * It accepts and replies with JSON
> * It interacts with some storage layer
# Haskell + Web Services = ???
> * Is it pleasant to build web services in Haskell?
> * Can it be nice to maintain these web services?
> * Will they be fast enough, and can they go faster?
> * Why, though?
# Goals
> * Show you the pieces
> * Show how they fit together
> * Make things run, break them, and fix them again
> * Create (and help you parse) **AMAZING** type errors
> * Let you decide: Is Haskell for Me?
> * and leave you with a reference
> * To build Haskell web services
# The Pieces
> * Setting up a project
> * Managing dependencies
> * Cabal
> * Stack
> * Directory structuring
> * Data modeling
> * Requests, Routes, Responses,
> * Controllers
> * Data storage
> * Everything else (!!)
# Setting Up
> * Make a directory
> * Go into that directory
> * Type: `cabal init`
> * Let's try this
# Project Categories: A Taxonomy of Things
> * You'll get to a point where Cabal asks: `Project category:`
> * There will be many options
> * This is a freeform field - think of it as a tag
> * Choose what feels right to you
# Cabal files
> * Let's take a look at [one](https://gitlab.com/cpp.cabrera/type-assisted-speed-runs/blob/master/type-assisted-speed-runs.cabal)
> * Lots of fields - some important ones
> * name
> * version
> * license
> * build-type: Simple
# Cabal files: Libraries
> * Your application is a library
> * This is why `library` gets a special place in Cabal files (only one per project)
> * Some important fields:
> * exposed-modules: public API
> * other-modules: part of build, but hidden from users
> * build-depends: third party dependencies
> * hs-source-dirs: where is the root of your source code?
> * ghc-options: compiler flags
# Managing Dependencies
> * Adding dependencies in Haskell is an organic process, esp. at first
> * Work on a project 'til you feel you need something else
> * Look around on [Hackage](http://hackage.haskell.org/packages/search)
> * Add it to the `build-depends` section of your cabal file
> * Rebuild (which we'll cover next)
# Stack: Welcome to Easy Mode
> * Up until about a month ago, Haskell project management involved lots of Cabal
> * Cabal is not user-friendly - lots of quirks
> * [stack](https://github.com/commercialhaskell/stack) appeared, which makes project management easier
> * All you need to get started (and keep going) - a Cabal file
# Stack and Your Project
> * Generate a `stack.yaml` using `stack init`
> * It recursively detects projects from your root
> * This is great for complex "*Enterprise*" applications
> * Build your project: `stack build`
> * Test your project: `stack test`
> * And much more
> * Let's take a look at stack in action
# Directory Structure
> * Now you have a project, and you want to grow it
> * Lots of room for creativity here
> * My suggestions:
> * Take advantage of project categories for generic parts: Data, Control, etc.
> * Put app-specific bits under API/ or AppName/
> * Examples: API/Models/User.hs, API/Database/User.hs, API/Errors.hs
# Growing the Project
> * Any time you add a new file, you have to manually add it to Cabal
> * Either of `exposed-modules`, `other-modules`
> * Any time you add a new dependency, you have to manually add it to Cabal
> * `build-depends`
> * Yes, this is tedious
> * Unfortunately, not yet a solved problem
> * Let's see what happens
# Data Modeling
> * You'll typically maintain up to 2 + n representations
> * Haskell Storage mapping type
> * Haskell core model data type
> * Haskell (Request|Response) data type, for each repr (JSON, XML, etc.)
> * The core model data type should be the richest
> * Frequently, repsonses will be a `newtype` over the model type
> * Similarly for the database layer
# Data Modeling: Take 2
> * It takes some practice before finding a good separation of layers
> * Leverage sum types wherever you can
> * These are your greatest allies for long-term maintenance
> * Let's take a look at a sum type in practice
# Data Modeling: Take 3
> * Where do we even start?
> * My suggestion: start with storage
> * What entities does your service care about?
> * How are they related?
> * What fields do they have?
> * What types do these fields have?
> * With that done, we can then map that to Haskell
> * Let's look at some SQL and then write some Haskell
# Appreciating Type Errors
> * Let's take a moment to explore some type errors
> * The key part is: compilers frequently have terrible error outputs
> * The other key part: learn to speak with your compiler
> * Development can be a dialogue
> * You can enrich the conversation by being as precise as you need
# Break Time
# Requests, Routes, Responses
> * We now have some data, some types, and some storage machinery
> * Let's connect it to the network
> * Depending on the route, we need to do some of the following
> * Parse the request into a data type
> * Store or modify some information
> * Respond, serializing our data as needed
# Controllers: Data Parsing
> * Sometimes, we want to accept JSON from connected clients
> * We want to make sure that the JSON the send us is valid
> * Let's write a route: POST /games/echo
> * Accepts a Game specified in JSON, w/ some optional fields
> * Parses it carefully
> * If successful, echoes the Game representation
> * Let's build that!
# Controllers: Creating Data
> * Let's look at a route that creates users: POST /register
> * We need to:
> * Parse a registration request: only query params needed
> * Interact with storage, generating a User on completion
> * Convert that User to JSON for a response
# Controllers: Fetching Data
> * Let's look at a route to view a particular user: GET /players/:id
> * We need to:
> * Parse a URL component, ensuring it is a valid UUID
> * Interact with storage, fetching user data
> * Convert the User to JSON for a response
# A Note on Responses: Language Agnostic Thoughts
> * This is a good time to talk about response contracts
> * Contracts, in this sense, refer to entity canonicity
> * There is only one representation per entity
> * Are you building a private web service?
> * Talk with your client-side team about what they need to consume
> * Are you building a public API?
> * Keep things as consistent as you can
> * Consider versioning
# Data Storage: No More Hand-Waving
> * Data storage, particularly when using SQL, is not straight-forward
> * There are many libraries, each approaching this problem differently
> * This is the part of your service that should probably have the most testing
> * Let's revisit some storage code from earlier
# Logging: An Easy Part
> * Decide on a format
> * Strategically insert log points
> * ???
> * Win
# Logging: More Details
> * Deciding on logging format is the key part
> * I start with the syslog [RFC](https://tools.ietf.org/html/rfc5424#section-6) for some fields
> * Level: info, warning, etc.
> * Timestamp
> * Host name
> * Project name
> * Process ID
> * Then add some context as needed
> * Provide a simple module for the rest of the application to use
> * Let's look at some logging code
# Errors: Computers Failing To This Day
> * They happen
> * When they happen, it's valuable to be informative and consistent
> * Good error reporting design shares much in common with good logging design
> * Let's look at some code!
# Trade-Offs in Error Handling
> * Haskell encourages a style of design that is total
> * This means: all cases are handled, no exceptions
> * But it also includes harder things to prove, like termination
> * It's up to you to decide how much safety you want
> * A suggestion: add tighter types when you encounter an error case at run-time
> * This is as effective as a unit test, but w/o regressions
# What I Didn't Cover
> * Authentication & Access Control
> * Application Configuration
> * Comparing alternative libraries
> * Profiling
> * Benchmarking
> * Debugging
> * Exception Handling
> * Automated testing
> * Inter-service communication
> * In-process caching
> * More structured logging
> * Advanced Abstraction: Free Monads, Transformers, etc.
> * Advanced type-safety
> * Totality
> * Additional tooling
# Next Steps
> * Read the (slowly) growing code for this [tutorial](https://gitlab.com/cpp.cabrera/type-assisted-speed-runs)
> * Play with the tutorial code; break it, add features, removes features
> * Write your own services, and vary the pieces
> * Formats: XML, CSV, YAML, msgpack
> * Storage: other SQL, other non-SQL, local disk, web storage providers (S3, etc.)
> * Front-end work
> * Making things is the best way to learn
> * It's okay to make mistakes
> * It's okay to do things differently
# Thank You
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment