Table of Contents
Course OverviewRichard Feldman begins the course by explaining that the workshop was created to help people who want to transition from using Elm as a hobby, to using it at work or at scale. The primary goals and an outline of the course are discussed, as well as the workshop's structure.
Module BoundariesRichard introduces how choosing whether or not to expose a custom type's variants from a module affects the guarantees you can enforce about that type.
Opaque TypesOpaque types are types whose implementation details are hidden from other modules. Richard gives examples of opaque types in core Elm libraries, only some of which are custom types under the hood.
Validated DataRichard shows how elm-validate uses a custom type called Valid to guarantee that forms have been run through a validation function before being submitted.
Handling Edge CasesRichard demonstrates through direct application why it's important to make it impossible for code to compile unless an edge case has been handled.
When Not to Go OpaqueRichard uses the example of Author custom type in the course repo to demonstrate a case where opaque types are not useful.
Opaque Types ExerciseStudents are instructed to make Cred an opaque type, then fix the resulting compiler errors.
Opaque Types SolutionRichard live-codes the solutions to the Opaque Types exercise.
Constraint UnificationElm's compiler performs type inference through a process called constraint unification. Richard walks through how it works.
Open & Closed RecordsClosed records define the exact shape of a record, whereas open records specify a minimum set of fields that must be present. Richard shows how these work with constraint unification.
Open RecordsRichard explains why open records are necessary in Elm. Although not designed for it, they are also used for naming arguments, and data modeling.
Extensible Custom TypesRichard demonstrates how a more extensible data shapes could be created with custom types than with an open record.
Questions & ReviewA clarification question is asked about the example that was last shown, Richard gives a word of caution about open records, and this section of the course is briefly reviewed.
Extensible Data ExerciseStudents are instructed to return and convert data using extensible data principles.
Extensible Data SolutionRichard live-codes the solution to the Extensible Data exercise.
Units of Measure & Phantom TypesUsing the Mars Climate Orbiter disaster as an application, Richard demonstrates how to use custom types to add measurement units to numbers, and contrasts this method with a refactored solution using phantom types.
Accessible HTMLThe tesk9/accessible-html library is introduced. Richard shows how the library uses type constraints to guarantee that semantically non-interactive HTML elements like paragraphs can never be given event handlers.
The Never TypeRichard shows how the Never type can be used to describe Tasks that are guaranteed never to fail.
Type Parameter DesignRichard summarizes the tradeoffs between accepting Attribute Msg, Attribute msg, and Attribute Never. Phantom types and non-phantom types are discussed, as well as how to use Never as a constraint to require that something is still unbound, and how that will unify with two different type variables.
Creating Constraints ExerciseStudents are instructed to convert a Task to a Cmd using Task.attempt or Task.perform.
Creating Constraints SolutionRichard live-codes the solution to the Creating Constraints exercise.
What Fits in Our HeadsRichard discusses the fundamental challenge of scaling: what happens when the codebase gets too big to fit in our heads?
Narrowing TypesNarrowing types are introduced as the key to scaling. Richard discusses the implications this can have on debugging. - couldn't find this cut...
Enforcement ArgumentsUsing the current codebase, Richard demonstrates how adding arguments can enforce business rules. He gives the example of adding a mandatory Cred (credentials) argument to certain Msg variants, to enforce that those variants can only be used when the user is logged in.
Using Modules for ModularityRichard discusses the benefits of organizing modules around a single type, and the cost of splitting modules based in file length rather than based on types.
Scaling ExerciseStudents are instructed to refactor three different files to accept narrower types than the entire Model.
Scaling SolutionRichard live-codes the solution to the Scaling exercise.
Helper FunctionsRichard walks through examples of the most important tool for reuse in Elm: the helper function. It works for view logic, update logic, and everything in between.
Similar vs the SameSometimes reuse is not best practice. Three different flavors of status are discussed. Richard shows some examples of similar code where reuse would result in excessive configuration.
Html msgWhen a view function returns an Html msg, it is reusable across pages and projects. Richard discusses two possibilities: either an unbounded type, or receiving a message.
Html.map & Cmd.mapRichard discusses the most powerful with the most overhead reuse method. When a view function needs several different message variants, returning Html msg can require excessive configuration. In these cases, Html.map and Cmd.map can replace the configuration with a one-time translation operation.
Reuse ExerciseStudents are instructed to refactor their code such that the concepts of reuse are utilized effectively.
Reuse SolutionRichard live-codes the solution to the Reuse exercise.
Sources of Truth
Impossible StatesWhen we have multiple sources of truth for the same information, our application can end up in states that ought to be impossible. Richard gives an example of how this can affect the tabs in the sample application.
Derived DataRichard explains why, given the option of rendering a value that is derived from another in view and throwing it away, this is a much better alternative than recording it in the model.
AuthenticationAuthentication is a case where the source of truth is on the server, but the client must cache the authentication token to get acceptable performance. Richard walks through what can happen if this cached information becomes invalid.
Caching ExerciseStudents are tasked with creating a single source of truth within the tab functionality in the application.
Caching SolutionRichard live-codes the solution to the Caching exercise.
Pipeline types & Decode.map3Richard shows how the Decode Pipeline types interact with the types of the Decoder primitives using Decode.map3.
Decode.succeedRichard compares the Decode.succeed function to Decode.map3, and explains the use cases.
Decode.map & Decode.andThenRichard explains that Decode.andThen works similarly to Decode.map, with the exception that it can additionally change successes to failures.
DecoderizingRichard shows how Decode.andThen can be used with a result to "decoderize" an operation.
Intermediate Representations & ReviewRichard uses the example application as a reference while explaining intermediate representations as for the idea of using internals only for the purpose of creating a decoder, not exposing it to the outside world as an intermediate step, then using Decode.map to convert to the one that the world sees.
Decoding ExerciseStudents are instructed to decode a Time.Posix value using Decode.andThen.
Decoding SolutionRichard live-codes the solution to the Decoding exercise.
RoutesRichard uses the example application to demonstrate how to define a Route custom type that represents the different URL pathways in the application, and how to parse URLs into them.
PagesDespite the name, Single-Page Apps have multiple logical "Pages" in them. Richard demonstrates how to model these in Elm. - Maybe 0:00-1:40 ? Cliffhanger??
Module StructureGreat Elm modules tend to be organized around a particular type. Richard uses the sample application to demonstrate how the modules in the example application are organized, and why the boundaries are drawn where they are.
Loading & Persisting DataThere are several possible strategies for loading and persisting data between pages. Richard discusses trade-offs between different strategies.
SPAs ExerciseThis exercise is intended to help students to become familiar with this DSL for going from URLs to Routes.
SPAs SolutionRichard live-codes the solution to the SPAs exercise.