<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Richard Feldman</title>
    <description>The latest articles on DEV Community by Richard Feldman (@rtfeldman).</description>
    <link>https://dev.to/rtfeldman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1841%2F1094080.png</url>
      <title>DEV Community: Richard Feldman</title>
      <link>https://dev.to/rtfeldman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rtfeldman"/>
    <language>en</language>
    <item>
      <title>What would you pay for type checking?</title>
      <dc:creator>Richard Feldman</dc:creator>
      <pubDate>Mon, 10 Feb 2020 14:24:10 +0000</pubDate>
      <link>https://dev.to/rtfeldman/what-would-you-pay-for-type-checking-2pg9</link>
      <guid>https://dev.to/rtfeldman/what-would-you-pay-for-type-checking-2pg9</guid>
      <description>&lt;p&gt;Here’s a statement that shouldn’t be controversial, but is anyway: &lt;strong&gt;JavaScript is a type-checked language.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ve heard people refer to JavaScript as “untyped” (implying that it has no concept of types), which is odd considering JS's most infamous error—“undefined is not a function”—is literally an example of the language reporting a type mismatch. How could a supposedly “untyped” language throw a &lt;code&gt;TypeError&lt;/code&gt;? Is JS aware of types or isn't it?&lt;/p&gt;

&lt;p&gt;Of course, the answer is that JavaScript is a type-checked language: its types are checked at runtime. The fact that the phrase “JavaScript is a type-checked language” can be considered controversial is evidence of the bizarre tribalism we’ve developed around when types get checked. I mean, is it not accurate to say that JavaScript checks types at runtime? Of course it's accurate! &lt;em&gt;Undefined is not a function!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Truly Untyped Languages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Assembly_language"&gt;Assembly language&lt;/a&gt; does not have “undefined is not a function.”&lt;/p&gt;

&lt;p&gt;This is because it has neither build time nor runtime type checking. It’s essentially a human-readable translation of &lt;a href="https://en.wikipedia.org/wiki/Machine_code"&gt;machine code&lt;/a&gt;, allowing you to write &lt;code&gt;add&lt;/code&gt; instead of having to handwrite out the number corresponding to an addition machine instruction.&lt;/p&gt;

&lt;p&gt;So what happens if you get a runtime type mismatch in Assembly? If it doesn’t check the types and report mismatches, like JavaScript does, what does it do?&lt;/p&gt;

&lt;p&gt;Let’s suppose I’ve written a function that capitalizes the first letter in a lowercase string. I then accidentally call this code on a number instead of a string. Whoops! Let’s compare what would happen in JavaScript and in Assembly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since Assembly doesn't have low-level primitives called “number” or “string,” let me be a bit more specific. For “number” I’ll use a 64-bit integer. For “string” I’ll use the definition C would use on a 64-bit system, namely “a 64-bit memory address pointing to a sequence of bytes ending in 0.” To keep the example brief, the function will assume the string is ASCII encoded and already begins with a lowercase character.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The assembly code for my “capitalize the first letter in the string” function would perform roughly the following steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat my one 64-bit argument as a memory address, and load the first byte from memory at that address.&lt;/li&gt;
&lt;li&gt;“Capitalize” that byte by subtracting 32 from it. (In ASCII, subtracting 32 from a lowercase letter’s character code makes it uppercase.)&lt;/li&gt;
&lt;li&gt;Write the resulting byte back to the original memory address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I call this function passing a “string” (that is, a memory address to the beginning of my bytes), these steps will work as intended. The function will capitalize the first letter of the string. Yay!&lt;/p&gt;

&lt;p&gt;If I call this function passing a normal integer…yikes. Here are the steps my Assembly code will once again faithfully perform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat my one 64-bit argument as a memory address, even though it’s actually supposed to be an integer. Load the first byte from whatever memory happens to be at that address. This may cause a &lt;a href="https://en.wikipedia.org/wiki/Segmentation_fault"&gt;segmentation fault&lt;/a&gt; (crashing the program immediately with the only error information being “Segmentation fault”) due to trying to read memory the operating system would not allow this process to read. Let’s proceed assuming the memory access happened to be allowed, and the program didn’t immediately crash.&lt;/li&gt;
&lt;li&gt;“Capitalize” whatever random byte of data we have now loaded by subtracting 32 from it. Maybe this byte happened to refer to a student's test score, which we just reduced by 32 points. Or maybe we happened to load a character from the middle of a different string in the program, and now instead of saying “Welcome, Dave!” the screen says “Welcome, $ave!” Who knows? The data we happen to load here will vary each time we run the program.&lt;/li&gt;
&lt;li&gt;Write the resulting byte back to the original memory address. Sorry, kid - your test score is just 32 points lower now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully we can all agree that “undefined is not a function” is a significant improvement over segmentation faults and corrupting random parts of memory. Runtime type checking can prevent &lt;a href="https://en.wikipedia.org/wiki/Memory_safety"&gt;memory safety&lt;/a&gt; problems like this, and much more.&lt;/p&gt;

&lt;p&gt;Bytes are bytes, and many machine instructions don’t distinguish between bytes of one type or another. Whether done at build time or at runtime, having some sort of type checking is the only way to prevent disaster when we’d otherwise instruct the machine to interpret the bytes the wrong way. “Types for bytes” was the original motivation for introducing type checking to programming, although it has long since grown beyond that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objective Costs of Checking Types
&lt;/h2&gt;

&lt;p&gt;It’s rare to find discussions of objective tradeoffs in the sea of “static versus dynamic” food fights, but this example actually illustrates one.&lt;/p&gt;

&lt;p&gt;As the name suggests, runtime type checking involves doing type checking…at runtime! The reason JavaScript wouldn’t cause a segmentation fault or corrupt data in this example, where Assembly would, is that JavaScript would generate more machine instructions than the Assembly version. Those instructions would record in memory the types of each value, and then before performing a certain operation, first read the type out of memory to decide whether to proceed with the operation or throw an error.&lt;/p&gt;

&lt;p&gt;This means that in JavaScript, a 64-bit number often takes up more than 64 bits of memory. There’s the memory needed to store the number itself, and then the extra memory needed to store its type. There’s also more work for the CPU to do: it has to read that extra memory and check the type before performing a given operation. In Python, for example, &lt;a href="https://code.tutsplus.com/tutorials/understand-how-much-memory-your-python-objects-use--cms-25609"&gt;a 64-bit integer takes up 192 bits&lt;/a&gt; (24 bytes) in memory.&lt;/p&gt;

&lt;p&gt;In contrast, build time type checking involves doing type checking…at build time! This does not have a runtime cost, but it does have a build-time cost; an objective downside to build-time type checking is that you have to wait for it.&lt;/p&gt;

&lt;p&gt;Programmer time is expensive, which implies that programmers being blocked waiting for builds is expensive. Elm’s compiler builds so fast that at &lt;a href="https://www.noredink.com"&gt;NoRedInk&lt;/a&gt; we’d have paid a serious &lt;a href="https://www.xkcd.com/303/"&gt;“code’s compiling”&lt;/a&gt; productivity tax if we had chosen TypeScript instead—to say nothing of what we’d have missed in terms of &lt;a href="https://youtu.be/a0039_JRAQo"&gt;programmer happiness&lt;/a&gt;, &lt;a href="https://elm-lang.org/news/blazing-fast-html-round-two"&gt;runtime performance&lt;/a&gt;, or the &lt;a href="https://youtu.be/5CYeZ2kEiOI"&gt;reliability of our product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That said, using a language without build-time checking will not necessarily cause you to spend less time waiting. &lt;a href="https://stripe.com/"&gt;Stripe&lt;/a&gt;’s programmers would commonly wait 10-20 seconds for one of their Ruby tests to execute, but &lt;a href="https://sorbet.org/"&gt;the Ruby type checker they created w&lt;/a&gt;as able to give actionable feedback on &lt;a href="https://blog.nelhage.com/post/reflections-on-performance/"&gt;their entire code base in that time&lt;/a&gt;. In practice, introducing build-time type checking apparently led them to spend less time overall on waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimizations for Type Checkers
&lt;/h2&gt;

&lt;p&gt;Both build time and runtime type checkers are programs, which means their performance can be optimized.&lt;/p&gt;

&lt;p&gt;For example, &lt;a href="https://en.wikipedia.org/wiki/Just-in-time_compilation"&gt;JIT compilers&lt;/a&gt; can reduce the cost of runtime type checking. JavaScript in 2020 runs multiple orders of magnitude faster than JavaScript in 2000 did, because a massive effort has gone into optimizing its runtime. Most of the gains have been outside the type checker, but JavaScript’s runtime type checking cost has gone down as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Conversely, between 2000 and 2020 JavaScript’s build times have exploded—also primarily outside type checking. When I first learned JavaScript (almost 20 years ago now, yikes!) it had no build step. The first time I used JS professionally, the entire project had &lt;a href="https://jquery.com"&gt;one dependency&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today, just installing the dependencies for &lt;a href="https://github.com/facebook/create-react-app"&gt;a fresh React project&lt;/a&gt; takes me over a minute—and that’s before even beginning to build the project itself, let alone type check it! By contrast, I can build a freshly git-cloned &lt;a href="https://github.com/rtfeldman/elm-spa-example"&gt;4,000-line Elm SPA&lt;/a&gt; in under 1 second total, including installing dependencies and full type checking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While they may improve performance overall, JIT compilers introduce their own runtime costs, and cannot make runtime type checking free. Arguably &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;‘s main reason for existence is to offer a reliable and ergonomic programming language which does not introduce the sort of runtime overhead that come with JIT compilers and garbage collectors.&lt;/p&gt;

&lt;p&gt;Build time type checkers are also programs, and their performance can also be optimized.&lt;/p&gt;

&lt;p&gt;We often lump build-time type checking performance into the bucket of “compilation time,” but type checking isn’t necessarily the biggest contributor to slow builds. For example, in the case of &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;, code generation is &lt;a href="https://pingcap.com/blog/rust-compilation-model-calamity/"&gt;apparently a much bigger contributor to compile times&lt;/a&gt; than type checking—and code generation only begins after type checking has fully completed.&lt;/p&gt;

&lt;p&gt;Some type checkers with essentially equivalent type systems build faster than others, because of performance optimization. For example, the 0.19.0 release of Elm did not change the type system at all, but massively improved build times by implementing &lt;a href="https://github.com/elm/compiler/blob/master/docs/upgrade-instructions/0.19.0.md#compiler-performance"&gt;certain performance optimizations&lt;/a&gt; which (among other things) made part of type inference take &lt;em&gt;O(1)&lt;/em&gt; time instead of &lt;a href="https://www.reddit.com/r/programming/comments/1f2ml3/what_does_olog_n_mean_exactly/ca691yj/"&gt;&lt;em&gt;O(log(n))&lt;/em&gt;&lt;/a&gt; time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Systems Influence Performance
&lt;/h2&gt;

&lt;p&gt;Type system design decisions aren’t free! At both build time and runtime, type checking performance is limited by the features of the type system itself.&lt;/p&gt;

&lt;p&gt;For example, researchers have developed &lt;a href="http://gallium.inria.fr/~fpottier/publis/emlti-final.pdf"&gt;type inference strategies that run very fast&lt;/a&gt;, but these strategies rely on some assumptions being true about the design of the type system. Introducing certain &lt;a href="https://en.wikipedia.org/wiki/Subtyping"&gt;subtyping&lt;/a&gt; features can invalidate these strategies, so offering such features lowers the ceiling on how fast the compiler can be—and for that matter, whether it can offer type inference.&lt;/p&gt;

&lt;p&gt;It’s easy to quip “you could guarantee that at build time using ________ types” (fill in the blank with something like &lt;a href="https://en.wikipedia.org/wiki/Substructural_type_system#Linear_type_systems"&gt;linear types&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Refinement_type"&gt;refinement types&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Dependent_type"&gt;dependent types&lt;/a&gt;, etc.) but the impact this would have on compilation times is less often discussed.&lt;/p&gt;

&lt;p&gt;If your language introduced a given type system feature tomorrow, what would the impact be on compile times? Has anyone developed a way to check those types quickly? How much value does a given feature need to add to compensate for the &lt;a href="https://www.xkcd.com/303/"&gt;swordfighting downtime&lt;/a&gt; it brings along with it?&lt;/p&gt;

&lt;p&gt;Runtime type checkers are subject to these tradeoffs as well. Python and Clojure have different type systems, for example. So do Ruby and Elixir, and JavaScript and Lua. The degree to which their performance can be optimized (by JIT compilers, for example) depends in part on the design of these type systems.&lt;/p&gt;

&lt;p&gt;Because it’s faster to check some type system features at runtime than at build time, these forces combine to put performance caps on languages which add build time checking to type systems which were designed only with runtime type checking in mind. For example, TypeScript’s compiler could run faster if it did not need to accommodate JavaScript’s existing type system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Would You Pay?
&lt;/h2&gt;

&lt;p&gt;Except when writing in a truly untyped language like Assembly, we’re all paying for type checking somewhere—whether at build time, at runtime, or both. That cost varies based on what performance optimizations have been done (such as build-time algorithmic improvements and runtime JITs), and while type system design choices can restrict which optimizations are available, they don’t directly cause performance to be fast or slow.&lt;/p&gt;

&lt;p&gt;Programming involves weighing lots of tradeoffs, and it’s often challenging to anticipate at the beginning of a project what will cause problems later. “The build runs too slowly” and “the application runs too slowly” are both serious problems to have, and which programming language you choose puts a cap on how much you can improve either.&lt;/p&gt;

&lt;p&gt;We all have different tolerances for how much we’re willing to pay for this checking, and what we expect to get out of it. It’s worth thinking critically about these tradeoffs, to make conscious decisions rather than choosing the same technology we chose last time because it’s familiar.&lt;/p&gt;

&lt;p&gt;So the next time you’re starting a project, think about these costs and benefits up front. What would you pay for type checking?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://www.brianthicks.com"&gt;Brian Hicks&lt;/a&gt;, &lt;a href="http://stoeffel.github.io"&gt;Christoph Hermann&lt;/a&gt;, &lt;a href="https://medium.com/@ckoster22"&gt;Charlie Koster&lt;/a&gt;, &lt;a href="https://lexi-lambda.github.io"&gt;Alexis King&lt;/a&gt;, and &lt;a href="https://hillelwayne.com"&gt;Hillel Wayne&lt;/a&gt; for reading drafts of this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>types</category>
    </item>
    <item>
      <title>Tour of an Open-Source Elm SPA</title>
      <dc:creator>Richard Feldman</dc:creator>
      <pubDate>Mon, 08 May 2017 07:47:20 +0000</pubDate>
      <link>https://dev.to/rtfeldman/tour-of-an-open-source-elm-spa</link>
      <guid>https://dev.to/rtfeldman/tour-of-an-open-source-elm-spa</guid>
      <description>&lt;p&gt;People often ask me if I can point them to an open-source Elm Single Page Application so they can peruse its code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.ilias.xyz/" rel="noopener noreferrer"&gt;Ilias van Peer&lt;/a&gt; linked me to the &lt;a href="https://github.com/gothinkster/realworld" rel="noopener noreferrer"&gt;Realworld&lt;/a&gt; project, which seemed perfect for this. They provide a back-end API, static markup, styles, and a spec, and you build a SPA front-end for it using your &lt;a href="https://www.youtube.com/watch?v=3FNKaGm3gk0" rel="noopener noreferrer"&gt;technology of choice&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the result. I had a ton of fun building it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rtfeldman/elm-spa-example" rel="noopener noreferrer"&gt;4,000 lines of delicious Elm single page application goodness&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fair warning:&lt;/strong&gt; This is not a gentle introduction to Elm. I built this to be something I'd like to maintain, and did not hold back. This is how I'd build this application with the full power of Elm at my fingertips.&lt;/p&gt;

&lt;p&gt;I gave a talk at Elm Europe about the principles I used to build this, and I highly recommend watching it! It's called &lt;a href="https://www.youtube.com/watch?v=DoA4Txr4GUs" rel="noopener noreferrer"&gt;&lt;strong&gt;Scaling Elm Apps&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're looking for a less drink-from-the-firehose introduction to Elm, I can recommend a &lt;a href="https://manning.com/books/elm-in-action?a_aid=elm_in_action&amp;amp;a_bid=b15edc5c" rel="noopener noreferrer"&gt;book&lt;/a&gt;, a &lt;a href="https://frontendmasters.com/courses/elm/?u=ea0ec073ea98046a6a26ccd9a0adede4d5458676" rel="noopener noreferrer"&gt;video tutorial&lt;/a&gt;, and of course the &lt;a href="https://guide.elm-lang.org" rel="noopener noreferrer"&gt;Official Guide&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing for User Experience
&lt;/h2&gt;

&lt;p&gt;I went with a routing design that optimizes for user experience. I considered three use cases, illustrated in this gif:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fin1hx0keuvtubk9rjyu9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fin1hx0keuvtubk9rjyu9.gif" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user has a fast connection&lt;/li&gt;
&lt;li&gt;The user has a slow connection&lt;/li&gt;
&lt;li&gt;The user is offline&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Fast Connection
&lt;/h3&gt;

&lt;p&gt;On fast connections, I want users to transition from one page to another seamlessly, without seeing a flash of a partially-loaded page in between.&lt;/p&gt;

&lt;p&gt;To accomplish this, I had each page expose &lt;code&gt;init : Task PageLoadError Model&lt;/code&gt;. When the router receives a request to transition to a new page, it doesn't transition immediately; instead, it first calls &lt;code&gt;Task.attempt&lt;/code&gt; on this &lt;code&gt;init&lt;/code&gt; task to fetch the data the new page needs.&lt;/p&gt;

&lt;p&gt;If the task fails, the resulting &lt;code&gt;PageLoadError&lt;/code&gt; tells the router what error message to show the user. If the task succeeds, the resulting &lt;code&gt;Model&lt;/code&gt; serves as the initial model necessary to render 100% of the new page right away.&lt;/p&gt;

&lt;p&gt;No flash of partially-loaded page necessary!&lt;/p&gt;

&lt;h3&gt;
  
  
  Slow Connection
&lt;/h3&gt;

&lt;p&gt;On slow connections, I want users to see a loading spinner, to reassure them that there's something happening even though it's taking a bit.&lt;/p&gt;

&lt;p&gt;To do this, I'm rendering a loading spinner in the header as soon as the user attempts to transition to a new page. It stays there while the &lt;code&gt;Task&lt;/code&gt; is in-flight, and then as soon as it resolves (either to the new page or to an error page), the spinner goes away.&lt;/p&gt;

&lt;p&gt;For a bit of polish, I prevented the spinner from flashing into view on fast connections by adding a CSS &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay" rel="noopener noreferrer"&gt;&lt;code&gt;animation-delay&lt;/code&gt;&lt;/a&gt; to the spinner's animation. This meant I could add it to the DOM as soon as the user clicked the link to transition (and remove it again once the destination page rendered), but the spinner would not become visible to the user unless a few hundred milliseconds of delay had elapsed in between.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offline
&lt;/h3&gt;

&lt;p&gt;I'd like at least some things to work while the user is offline.&lt;/p&gt;

&lt;p&gt;I didn't go as far as to use Service Worker (or for that matter App Cache, for those of us who &lt;a href="https://www.youtube.com/watch?v=WqV5kqaFRDU" rel="noopener noreferrer"&gt;went down that bumpy road&lt;/a&gt;), but I did want users to be able to visit pages like &lt;em&gt;New Post&lt;/em&gt; which could be loaded without fetching data from the network.&lt;/p&gt;

&lt;p&gt;For them, &lt;code&gt;init&lt;/code&gt; returned a &lt;code&gt;Model&lt;/code&gt; instead of a &lt;code&gt;Task PageLoadError Model&lt;/code&gt;. That was all it took.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubodjuxdxhrcfhvb5zhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubodjuxdxhrcfhvb5zhn.png" alt="Module structure: Data, Page, Request, and Views directories, along with Main.elm, Ports.elm, Route.elm, and Util.elm" width="248" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have over 100,000 lines of Elm code in production at &lt;a href="http://tech.noredink.com/post/136615783598/welcome-evan" rel="noopener noreferrer"&gt;NoRedInk&lt;/a&gt;, and we've learned a lot along the way! (We don't have a SPA, so our routing logic lives on the server, but the rest is the same.) Naturally every application is different, but I've been really happy with how well our code base has scaled, so I drew on our organizational scheme when building this app.&lt;/p&gt;

&lt;p&gt;Keep in mind that although using &lt;code&gt;exposing&lt;/code&gt; to &lt;a href="https://youtu.be/IcgmSRJHu_8" rel="noopener noreferrer"&gt;create guarantees by restricting what modules expose&lt;/a&gt; is an important technique (which I used often here), the actual file structure is a lot less important. Remember, if you change your mind and want to rename some files or shift directories around, Elm's compiler will have your back. It'll be okay!&lt;/p&gt;

&lt;p&gt;Here's how I organized this application's modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Page.*&lt;/code&gt; modules
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Examples:&lt;/em&gt; &lt;code&gt;Page.Home&lt;/code&gt;, &lt;code&gt;Page.Article&lt;/code&gt;, &lt;code&gt;Page.Article.Editor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These modules hold the logic for the individual pages in the app.&lt;/p&gt;

&lt;p&gt;Pages that require data from the server expose an &lt;code&gt;init&lt;/code&gt; function, which returns a &lt;code&gt;Task&lt;/code&gt; responsible for loading that data. This lets the routing system wait for a page's data to finish loading before switching to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Views.*&lt;/code&gt; modules
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Examples:&lt;/em&gt; &lt;code&gt;Views.Form&lt;/code&gt;, &lt;code&gt;Views.Errors&lt;/code&gt;, &lt;code&gt;Views.User.Follow&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These modules hold reusable views which multiple &lt;code&gt;Page&lt;/code&gt; modules import.&lt;/p&gt;

&lt;p&gt;Some, like &lt;code&gt;Views.User&lt;/code&gt;, are very simple. Others, like &lt;code&gt;Views.Article.Feed&lt;/code&gt;, are very complex. Each exposes an appropriate API for its particular requirements.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Views.Page&lt;/code&gt; module exposes a &lt;code&gt;frame&lt;/code&gt; function which wraps each page in a header and footer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Data.*&lt;/code&gt; modules
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Examples:&lt;/em&gt; &lt;code&gt;Data.User&lt;/code&gt;, &lt;code&gt;Data.Article&lt;/code&gt;, &lt;code&gt;Data.Article.Comment&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These modules describe common data structures, and expose ways to translate them into other data structures. &lt;code&gt;Data.User&lt;/code&gt; describes a &lt;code&gt;User&lt;/code&gt;, as well as the encoders and decoders that serialize and deserialize a &lt;code&gt;User&lt;/code&gt; to and from JSON.&lt;/p&gt;

&lt;p&gt;Identifiers such as &lt;code&gt;CommentId&lt;/code&gt;, &lt;code&gt;Username&lt;/code&gt;, and &lt;code&gt;Slug&lt;/code&gt; - which are used to uniquely identify comments, users, and articles, respectively - are implemented as union types. If we used e.g. &lt;code&gt;type alias Username = String&lt;/code&gt;, we could mistakenly pass a &lt;code&gt;Username&lt;/code&gt; to an API call expecting a &lt;code&gt;Slug&lt;/code&gt;, and it would still compile. We can rule bugs like that out by implementing identifiers as union types.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Request.*&lt;/code&gt; modules
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Examples:&lt;/em&gt; &lt;code&gt;Request.User&lt;/code&gt;, &lt;code&gt;Request.Article&lt;/code&gt;, &lt;code&gt;Request.Article.Comments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These modules expose functions to make HTTP requests to the app server. They expose &lt;code&gt;Http.Request&lt;/code&gt; values so that callers can combine them together, for example on pages which need to hit multiple endpoints to load all their data.&lt;/p&gt;

&lt;p&gt;I don't use raw API endpoint URL strings anywhere outside these modules. Only &lt;code&gt;Request.*&lt;/code&gt; modules should know about actual endpoint URLs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Route&lt;/code&gt; module
&lt;/h3&gt;

&lt;p&gt;This exposes functions to translate URLs in the browser's Location bar to logical "pages" in the application, as well as functions to effect Location bar changes.&lt;/p&gt;

&lt;p&gt;Similarly to how &lt;code&gt;Request&lt;/code&gt; modules never expose raw API URL strings, this module never exposes raw Location bar URL strings either. Instead it exposes a union type called &lt;code&gt;Route&lt;/code&gt; which callers use to specify which page they want.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Ports&lt;/code&gt; module
&lt;/h3&gt;

&lt;p&gt;Centralizing all the ports in one &lt;code&gt;port module&lt;/code&gt; makes it easier to keep track of them. Most large applications end up with more than just two ports, but in this application I only wanted two. See &lt;code&gt;index.html&lt;/code&gt; for the 10 lines of JavaScript code they connect to.&lt;/p&gt;

&lt;p&gt;At NoRedInk our policy for both ports and flags is to use &lt;code&gt;Value&lt;/code&gt; to type any values coming in from JavaScript, and decode them in Elm. This way we have full control over how to deal with any surprises in the data. I followed that policy here.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Main&lt;/code&gt; module
&lt;/h3&gt;

&lt;p&gt;This kicks everything off, and calls &lt;code&gt;Cmd.map&lt;/code&gt; and &lt;code&gt;Html.map&lt;/code&gt; on the various &lt;code&gt;Page&lt;/code&gt; modules to switch between them.&lt;/p&gt;

&lt;p&gt;Based on discussions around how asset management features like code splitting and lazy loading have been shaping up, I expect most of this file to become unnecessary in a future release of Elm.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Util&lt;/code&gt; module
&lt;/h3&gt;

&lt;p&gt;These are miscellaneous helpers that are used in several other modules.&lt;/p&gt;

&lt;p&gt;It might be more honest to call this &lt;code&gt;Misc.elm&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With server-side rendering, it's possible to offer a better user experience on first page load by using cookie-based authentication. There are &lt;a href="https://dev.to/rtfeldman/defense-against-the-dark-arts-csrf-attacks"&gt;security risks&lt;/a&gt; on that path, though!&lt;/li&gt;
&lt;li&gt;If I were making this from scratch, I'd use &lt;a href="http://package.elm-lang.org/packages/rtfeldman/elm-css/latest" rel="noopener noreferrer"&gt;&lt;code&gt;elm-css&lt;/code&gt;&lt;/a&gt; to style it. However, since Realworld provided so much markup, I ended up using &lt;a href="https://mbylstra.github.io/html-to-elm/" rel="noopener noreferrer"&gt;&lt;code&gt;html-to-elm&lt;/code&gt;&lt;/a&gt; to save myself a bunch of time instead.&lt;/li&gt;
&lt;li&gt;There's a beta of &lt;code&gt;elm-test&lt;/code&gt; in progress, and I'd like to use the latest and greatest for tests. I debated waiting until the new &lt;code&gt;elm-test&lt;/code&gt; landed to publish this, but decided that even in its untested form it would be a useful resource.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this has been useful to you!&lt;/p&gt;

&lt;p&gt;And now, back to writing another chapter of &lt;a href="https://www.manning.com/books/elm-in-action?a_aid=elm_in_action&amp;amp;a_bid=b15edc5c" rel="noopener noreferrer"&gt;Elm in Action&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>elm</category>
      <category>spa</category>
      <category>webapp</category>
      <category>scaling</category>
    </item>
    <item>
      <title>Defense Against the Dark Arts: CSRF Attacks</title>
      <dc:creator>Richard Feldman</dc:creator>
      <pubDate>Mon, 17 Apr 2017 03:42:39 +0000</pubDate>
      <link>https://dev.to/rtfeldman/defense-against-the-dark-arts-csrf-attacks</link>
      <guid>https://dev.to/rtfeldman/defense-against-the-dark-arts-csrf-attacks</guid>
      <description>&lt;p&gt;After an unspecified "werewolf incident" we have become the new maintainer of the &lt;code&gt;hogwarts.edu&lt;/code&gt; web app.&lt;/p&gt;

&lt;p&gt;Our first day on the job begins with Professor Dumbledore approaching us, explaining that his official &lt;code&gt;hogwarts.edu&lt;/code&gt; account has recently begun sending mysterious messages such as "Potter sux, Malfoy rulez" to all the students.&lt;/p&gt;

&lt;p&gt;As Dumbledore has an administrator account, this security hole could lead to much worse problems than pranks. He's asked us to fix the vulnerability before someone exploits it to cause more serious damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Authentication
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29yo6n1nd0ezh3nzooc5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29yo6n1nd0ezh3nzooc5.jpg" alt="Authenticatus Userum"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first thing we do is look at the server-side code that handles posting messages. It's very simple. Here's what it does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/dumbledore/send-message?to=all_students&amp;amp;msg=blahblah"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;"blahblah"&lt;/code&gt; (or whatever the &lt;code&gt;msg&lt;/code&gt; parameter was set to) from &lt;code&gt;@dumbledore&lt;/code&gt; to all students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's no attempt to check whether the request actually came from the owner of the &lt;code&gt;@dumbledore&lt;/code&gt; account, meaning any attacker can send a HTTP request to &lt;code&gt;hogwarts.edu/dumbledore/send-message&lt;/code&gt; and it will be treated as legitimate. Possibly our werewolf predecessor thought this would be fine.&lt;/p&gt;

&lt;p&gt;To prevent this from happening in the future, we introduce an authentication system.&lt;/p&gt;

&lt;p&gt;First we add a Secret Authentication Key to each user's account, which we randomly generate when the user logs in and delete when they log out.&lt;/p&gt;

&lt;p&gt;We've heard that &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" rel="noopener noreferrer"&gt;cookies&lt;/a&gt; have security problems, so we don't go down that road. Instead, when the user logs in, we record this key in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/a&gt; and have some JavaScript code include it as a header called &lt;code&gt;"secret-authentication-key"&lt;/code&gt; in our (legitimate) HTTP requests.&lt;/p&gt;

&lt;p&gt;Next we add a step to our server-side logic to verify the key. Our new process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/dumbledore/send-message?to=all_students&amp;amp;msg=blahblah"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"secret-authentication-key"&lt;/code&gt; and make sure it matches the Secret Authentication Key we stored in the database for the &lt;code&gt;@dumbledore&lt;/code&gt; account. If it doesn't match, reject the request.&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;"blahblah"&lt;/code&gt; (or whatever came after the &lt;code&gt;msg&lt;/code&gt; parameter) from &lt;code&gt;@dumbledore&lt;/code&gt; to all the students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now when we try to send phony messages as Dumbledore, the server rejects them for lacking the proper authentication key. When Dumbledore himself logs in and tries to send them himself, it works. Huzzah!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Cookies
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmoni4di1z8c3l5d5jpo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmoni4di1z8c3l5d5jpo.jpg" alt="Pageloadum Fasterosa"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The day after we roll out this new authentication scheme, Professor Snape apparates with a complaint. When he visits &lt;code&gt;hogwarts.edu/snape/messages&lt;/code&gt; to view his private messages, there's now a brief loading spinner before his messages show up. Snape demands that we put it back to the old way, where the messages loaded immediately.&lt;/p&gt;

&lt;p&gt;Why did we add the loading spinner? Well, we realized &lt;code&gt;hogwarts.edu/snape/messages&lt;/code&gt; was also unsecured, so naturally we secured it with our new &lt;code&gt;"secret-authentication-key"&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;The trouble is, when Snape visits &lt;code&gt;hogwarts.edu/snape/messages&lt;/code&gt; the browser doesn't know how to send that custom header in that initial HTTP request to the server. Instead, the server sends back some HTML containing a loading spinner and some JavaScript. The JavaScript reads the key out of &lt;code&gt;localStorage&lt;/code&gt; and makes a &lt;em&gt;second&lt;/em&gt; request (this time setting the &lt;code&gt;"secret-authentication-key"&lt;/code&gt; header), which is finally allowed to fetch Snape's messages from the server.&lt;/p&gt;

&lt;p&gt;While that second request is processing, all Snape sees is that rage-inducing spinner.&lt;/p&gt;

&lt;p&gt;We fix this usability problem by replacing our custom &lt;code&gt;"secret-authentication-key"&lt;/code&gt; header with the &lt;code&gt;Cookie&lt;/code&gt; header. Now when Snape logs in, we no longer use &lt;code&gt;localStorage&lt;/code&gt; - or for that matter any JavaScript at all - to store the key. Instead, our server puts a &lt;code&gt;"Set-Cookie: key_info_goes_here"&lt;/code&gt; header in the response; the browser knows that when it sees a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie" rel="noopener noreferrer"&gt;&lt;code&gt;Set-Cookie&lt;/code&gt; header&lt;/a&gt; on a HTTP response, it should persist the key on Snape's machine, in the form of a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" rel="noopener noreferrer"&gt;cookie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now whenever Snape's browser makes a HTTP request to &lt;code&gt;hogwarts.edu&lt;/code&gt;, it will automatically send the contents of that cookie in a &lt;code&gt;Cookie&lt;/code&gt; header. This is true even for the original &lt;code&gt;HTTP GET&lt;/code&gt; request it makes when Snape visits &lt;code&gt;hogwarts.edu/snape/messages&lt;/code&gt; - meaning that now our server can authenticate him right there on that first request, and serve the messages in the first response without needing a second HTTP roundtrip.&lt;/p&gt;

&lt;p&gt;Here's our new process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/snape/send-message?to=all_students&amp;amp;msg=blahblah"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"Cookie"&lt;/code&gt; and make sure it matches the Secret Authentication Key we stored in the database for the &lt;code&gt;@snape&lt;/code&gt; account. If it doesn't match, reject the request.&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;"blahblah"&lt;/code&gt; (or whatever came after the &lt;code&gt;msg&lt;/code&gt; parameter) from &lt;code&gt;@snape&lt;/code&gt; to all the students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Performance problem solved!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Cookie GET Vulnerabilities
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskoxwkl2rc5maqfo63co.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskoxwkl2rc5maqfo63co.jpg" alt="Cross Site Request Forgerio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wasn't there some reason we hadn't used cookies in the first place? Oh, right. Security concerns.&lt;/p&gt;

&lt;p&gt;Sure enough, the day after we roll out our cookie-based solution, Professor McGonagall turns up with a strange story. Just after she visited Draco Malfoy's blog, her official &lt;code&gt;hogwarts.edu&lt;/code&gt; account sent another of those "Potter sux, Malfoy rulez" messages to all students. How could this have happened?&lt;/p&gt;

&lt;p&gt;Although cookies solved our performance problem, they also opened us up to a new angle of attack: Cross-Site Request Forgeries, or &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)" rel="noopener noreferrer"&gt;CSRF attacks&lt;/a&gt; for short. (Commonly pronounced "C-Surf.")&lt;/p&gt;

&lt;p&gt;Viewing the HTML source code of Draco's blog, we notice this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="http://hogwarts.edu/mcgonagall/send-message?to=all_students&amp;amp;msg=Potter_sux"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As soon as Professor McGonagall visited his blog, her browser did what it always does when it encounters an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;: send a &lt;code&gt;HTTP GET&lt;/code&gt; request to the URL specified in its &lt;code&gt;src&lt;/code&gt;. Because the browser is sending this request to &lt;code&gt;hogwarts.edu&lt;/code&gt;, it automatically includes Professor McGonagall's stored authentication cookie in the &lt;code&gt;Cookie&lt;/code&gt; header. Our server checks to see if the cookie matches - which of course it does - and dutifully posts the malicious message.&lt;/p&gt;

&lt;p&gt;Argh!&lt;/p&gt;

&lt;p&gt;Avoiding this form of CSRF attack is one reason it's important that all our &lt;code&gt;GET&lt;/code&gt; requests do not result in our server taking any important actions. They should be pretty much read-only, give or take perhaps some logging.&lt;/p&gt;

&lt;p&gt;We can fix this by adding a new second step to our list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/mcgonagall/send-message?to=all_students&amp;amp;msg=blahblah"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If it is not a &lt;code&gt;POST&lt;/code&gt; request, &lt;a href="https://httpstatuses.com/405" rel="noopener noreferrer"&gt;reject it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"Cookie"&lt;/code&gt; and make sure it matches the Secret Authentication Key we stored in the database for the &lt;code&gt;@mcgonagall&lt;/code&gt; account. If it doesn't match, reject the request.&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;"blahblah"&lt;/code&gt; (or whatever came after the &lt;code&gt;msg&lt;/code&gt; parameter) from &lt;code&gt;@mcgonagall&lt;/code&gt; to all the students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Great! Now the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; CSRF attack no longer works, because &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; only ever results in &lt;code&gt;GET&lt;/code&gt; requests to load the &lt;code&gt;src&lt;/code&gt;. Professor McGonagall should be able to visit Draco's blog again with no problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Cookie POST Vulnerabilities
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs49o5ohilrcmqi9hwuh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs49o5ohilrcmqi9hwuh.jpg" alt="Form Exploitus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, a few days later, Draco has found a workaround. He replaced the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag with a form instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form method="POST" action="http://hogwarts.edu/mcgonagall/send-message?to=all_students&amp;amp;msg=Potter_sux"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He also put some JavaScript on the page which silently submits this &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; as soon as the page loads. As soon as Professor McGonagall visits the page, her browser submits this form - resulting in a &lt;code&gt;HTTP POST&lt;/code&gt; which automatically includes the cookie as usual - and our server once again posts the message.&lt;/p&gt;

&lt;p&gt;Double argh!&lt;/p&gt;

&lt;p&gt;In an effort to make things a bit more difficult, we change the &lt;code&gt;msg&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; fields from URL query parameters to requiring that this information be sent via JSON in the body of the request. This fixes the problem for another day or two, but Draco quickly gets wise and puts the JSON in a &lt;code&gt;&amp;lt;input type="hidden"&amp;gt;&lt;/code&gt; inside the form. We're back to square one.&lt;/p&gt;

&lt;p&gt;We consider changing the endpoint from &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;PUT&lt;/code&gt;, since &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; only supports &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;, but semantically this clearly makes more sense as a &lt;code&gt;POST&lt;/code&gt;. We try upgrading to HTTPS (doesn't fix it) and using something called &lt;a href="https://en.wikipedia.org/wiki/Secure_cookies" rel="noopener noreferrer"&gt;"secure cookies"&lt;/a&gt; (still doesn't fix it), and eventually stumble upon OWASP's &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)#Prevention_measures_that_do_NOT_work" rel="noopener noreferrer"&gt;list of other approaches that do not solve this problem&lt;/a&gt; before finally finding something that &lt;em&gt;does&lt;/em&gt; work.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Enforcing Same Origin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzj6tgc5ztmks67jsfdg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzj6tgc5ztmks67jsfdg.jpg" alt="Same Origin Enforcio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OWASP has some &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet" rel="noopener noreferrer"&gt;clear recommendations on how to defend against CSRF attacks&lt;/a&gt;. The most reliable form of defense is verifying that the request was sent by code running on a &lt;code&gt;hogwarts.edu&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;When browsers send HTTP requests, those requests include at least one (and possibly both, depending on whether it was an HTTPS request and how old the browser is) of these two headers: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer" rel="noopener noreferrer"&gt;&lt;code&gt;Referer&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin" rel="noopener noreferrer"&gt;&lt;code&gt;Origin&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the HTTP Request was created when the user was on a &lt;code&gt;hogwarts.edu&lt;/code&gt; page, then &lt;code&gt;Referer&lt;/code&gt; and &lt;code&gt;Origin&lt;/code&gt; will begin with &lt;code&gt;https://hogwarts.edu&lt;/code&gt;. If it was created when the user was viewing a non-&lt;code&gt;hogwarts.edu&lt;/code&gt; page such as Draco's blog, then the browser will dutifully set the &lt;code&gt;Referer&lt;/code&gt; and &lt;code&gt;Origin&lt;/code&gt; headers to the domain of his blog rather than &lt;code&gt;hogwarts.edu&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we require that &lt;code&gt;Referer&lt;/code&gt; and &lt;code&gt;Origin&lt;/code&gt; be set to &lt;code&gt;hogwarts.edu&lt;/code&gt;, we can reject all HTTP requests that originated from Draco's blog (or any other third-party site) as malicious.&lt;/p&gt;

&lt;p&gt;Let's add this check to our algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/mcgonagall/send-message"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If it is not a &lt;code&gt;POST&lt;/code&gt; request, reject it.&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;Origin&lt;/code&gt; and/or &lt;code&gt;Referer&lt;/code&gt; headers are present, verify that they match &lt;code&gt;hogwarts.edu&lt;/code&gt;. If neither is present, per &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Checking_the_Origin_Header" rel="noopener noreferrer"&gt;OWASP's recommendation&lt;/a&gt;, assume the request is malicious and &lt;a href="https://httpstatuses.com/400" rel="noopener noreferrer"&gt;reject it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"Cookie"&lt;/code&gt; and make sure it matches the Secret Authentication Key we stored in the database for the &lt;code&gt;@mcgonagall&lt;/code&gt; account. If it doesn't match, &lt;a href="https://httpstatuses.com/403" rel="noopener noreferrer"&gt;reject the request&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Send a message from &lt;code&gt;@mcgonagall&lt;/code&gt; based on the JSON in the request body.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Great! Now if a request comes from outside the browser, it won't have the necessary &lt;code&gt;Cookie&lt;/code&gt; header, and if it comes from inside the browser by way of Draco Malfoy's malicious blog, it won't pass the &lt;code&gt;Referer&lt;/code&gt; / &lt;code&gt;Origin&lt;/code&gt; Same Origin header check.&lt;/p&gt;

&lt;p&gt;Importantly, we should not perform this Same Origin check on &lt;em&gt;all&lt;/em&gt; requests.&lt;/p&gt;

&lt;p&gt;If we did it on all &lt;code&gt;GET&lt;/code&gt; requests, for example, then no one could link to &lt;code&gt;hogwarts.edu&lt;/code&gt; pages from different websites, as they would be rejected for having a different &lt;code&gt;Referer&lt;/code&gt;! We only want to do this Same Origin check for endpoints that no one should ever be able to access from outside a &lt;code&gt;hogwarts.edu&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;This is why it's so important that &lt;code&gt;GET&lt;/code&gt; requests be essentially "read-only" - anytime we have to skip this Same Origin check, Draco can use the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; trick from earlier to cause the endpoint's logic to run. If all that logic does is return information, then the result will be nothing more than a broken-looking &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; on Draco's blog. On the other hand, if the result is that messages get sent from the current user's account, that means an attacker can potentially use CSRF to send messages from the current user's account!&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Second Line of Defense
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F886n7zwpr2aksptd43l4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F886n7zwpr2aksptd43l4.jpg" alt="Custom Headero"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although OWASP does not list any known ways an attacker could circumvent this Same Origin Check defense (other than a successful &lt;a href="https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)" rel="noopener noreferrer"&gt;Cross-Site Scripting attack&lt;/a&gt;, which must be defended against separately, as &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Warning:_No_Cross-Site_Scripting_.28XSS.29_Vulnerabilities" rel="noopener noreferrer"&gt;such an attack can circumvent any number of CSRF countermeasures&lt;/a&gt;), they still recommend "a second check as an additional precaution to really make sure."&lt;/p&gt;

&lt;p&gt;One good reason to have a second check is that browsers can have bugs. Occasionally these bugs result in new vulnerabilities which attackers exploit, and it's always possible that someone might someday uncover a vulnerability in a popular browser allowing them to spoof the &lt;code&gt;Origin&lt;/code&gt; and &lt;code&gt;Referer&lt;/code&gt; headers.&lt;/p&gt;

&lt;p&gt;Having a second line of defense means that if our first line of defense becomes suddenly compromised, we already have a backup defense in place while browser vendors work on patching the vulnerability.&lt;/p&gt;

&lt;p&gt;The easiest to implement of OWASP's recommended supplemental defense measures is &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers" rel="noopener noreferrer"&gt;Custom Request Headers&lt;/a&gt;. Here's how it works.&lt;/p&gt;

&lt;p&gt;When the browser sends HTTP requests via &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest?redirectlocale=en-US&amp;amp;redirectslug=DOM%2FXMLHttpRequest" rel="noopener noreferrer"&gt;&lt;code&gt;XMLHttpRequest&lt;/code&gt;&lt;/a&gt; (aka XHR aka AJAX Request) they are forced to obey the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" rel="noopener noreferrer"&gt;Same-origin Policy&lt;/a&gt;. In contrast, HTTP requests sent via &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, and other elements have no such restriction. This means that even though Draco can put a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; on his blog which submits a HTTP request to &lt;code&gt;hogwarts.edu&lt;/code&gt;, he can't have his blog use an XHR to send requests to &lt;code&gt;hogwarts.edu&lt;/code&gt;. (That is, unless we've explicitly configured &lt;code&gt;hogwarts.edu&lt;/code&gt; to enable &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS" rel="noopener noreferrer"&gt;Cross-Origin Resource Sharing&lt;/a&gt;, which of course we haven't.)&lt;/p&gt;

&lt;p&gt;Great! Now we know that if we can be sure that our request came from a XHR rather than something like a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, it must have originated from &lt;code&gt;hogwarts.edu&lt;/code&gt; (assuming a valid &lt;code&gt;Cookie&lt;/code&gt; header, of course) regardless of what the &lt;code&gt;Origin&lt;/code&gt; or &lt;code&gt;Referer&lt;/code&gt; headers say.&lt;/p&gt;

&lt;p&gt;By default, there's no way to tell that a request came from an XHR or not. A &lt;code&gt;POST&lt;/code&gt; from a vanilla XHR is indistinguishable from a &lt;code&gt;POST&lt;/code&gt; from a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;. However, XHR supports a feature that &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; doesn't: configuring custom headers.&lt;/p&gt;

&lt;p&gt;By having our our XHR set a &lt;code&gt;"Content-Type: application/json"&lt;/code&gt; header (which is a semantically sensible header for us to send regardless, since we are sending JSON now), we will have created a HTTP request that a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; could not have created. If our server then checks for a &lt;code&gt;"Content-Type: application/json"&lt;/code&gt; header, that will be enough to ensure the request came from an XHR. If it came from an XHR, then it must have respected the Same-origin Policy, and therefore must have come from a &lt;code&gt;hogwarts.edu&lt;/code&gt; page!&lt;/p&gt;

&lt;p&gt;This method is a better Second Line of Defense than a First Line of Defense, because &lt;a href="https://hackerone.com/reports/44146" rel="noopener noreferrer"&gt;it can be circumvented via Flash&lt;/a&gt;. So we definitely shouldn't skip the &lt;code&gt;Origin&lt;/code&gt; / &lt;code&gt;Referer&lt;/code&gt; Same Origin check! We should use this only as an added layer of defense against a theoretical future vulnerability in &lt;code&gt;Origin&lt;/code&gt; / &lt;code&gt;Referer&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Process
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6d1quuizdb601o45ke4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6d1quuizdb601o45ke4.jpg" alt="Defendio CSRF"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's our final server-side process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for a HTTP request to &lt;code&gt;"hogwarts.edu/mcgonagall/send-message&lt;/code&gt;"&lt;/li&gt;
&lt;li&gt;If it is not a &lt;code&gt;POST&lt;/code&gt; request, &lt;a href="https://httpstatuses.com/405" rel="noopener noreferrer"&gt;reject it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;Origin&lt;/code&gt; and/or &lt;code&gt;Referer&lt;/code&gt; headers are present, verify that they match &lt;code&gt;hogwarts.edu&lt;/code&gt;. If neither is present, assume the request is malicious and &lt;a href="https://httpstatuses.com/400" rel="noopener noreferrer"&gt;reject it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"Content-Type"&lt;/code&gt; and make sure it is set to &lt;code&gt;application/json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check for a header called &lt;code&gt;"Cookie"&lt;/code&gt; and make sure it matches the Secret Authentication Key we stored in the database for the &lt;code&gt;@mcgonagall&lt;/code&gt; account. If it doesn't match, &lt;a href="https://httpstatuses.com/403" rel="noopener noreferrer"&gt;reject the request&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Send a message from &lt;code&gt;@mcgonagall&lt;/code&gt; based on the JSON in the request body.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This covers our current use case, but there are other things to keep in mind for potential future needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If someday we want to use an actual &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; ourselves (instead of an XHR), and we still want a second line of defense on top of the Same Origin check, we can &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Synchronizer_.28CSRF.29_Tokens" rel="noopener noreferrer"&gt;use a synchronizer token&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If we still want to use an XHR but don't want to set a custom header (like &lt;code&gt;Content-Type&lt;/code&gt;), or use a &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Synchronizer_.28CSRF.29_Tokens" rel="noopener noreferrer"&gt;synchronizer token&lt;/a&gt;, we can use a &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Double_Submit_Cookie" rel="noopener noreferrer"&gt;double submit cookie&lt;/a&gt; or an &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Encrypted_Token_Pattern" rel="noopener noreferrer"&gt;encrypted token&lt;/a&gt; instead.&lt;/li&gt;
&lt;li&gt;If we want to support &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS" rel="noopener noreferrer"&gt;CORS&lt;/a&gt;, well...then we need to totally rethink our authentication approach!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;hogwarts.edu&lt;/code&gt; is now in much better shape. Here's what we've done:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introduced an authentication system to prevent attackers from impersonating users.&lt;/li&gt;
&lt;li&gt;Used cookies to do this in a way that does not require two HTTP roundtrips (with a loading spinner in between) to view pages with private information, like a page listing a user's private messages.&lt;/li&gt;
&lt;li&gt;Defended against &lt;code&gt;&amp;lt;img src="some-endpoint-here"&amp;gt;&lt;/code&gt; &lt;code&gt;GET&lt;/code&gt; CSRF attacks by requiring that endpoints which make changes to things use HTTP verbs other than &lt;code&gt;GET&lt;/code&gt;. (In this case, we used &lt;code&gt;POST&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;Defended against &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; &lt;code&gt;POST&lt;/code&gt; CSRF attacks by checking that the &lt;code&gt;Origin&lt;/code&gt; and/or &lt;code&gt;Referer&lt;/code&gt; headers match &lt;code&gt;hogwarts.edu&lt;/code&gt; (and rejecting the request if neither header is present).&lt;/li&gt;
&lt;li&gt;Added a second line of defense against future potential &lt;code&gt;Origin&lt;/code&gt; and/or &lt;code&gt;Referer&lt;/code&gt; vulnerabilities by requiring that the &lt;code&gt;Content-Type&lt;/code&gt; header be set to &lt;code&gt;application/json&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With all of these put together, we now have some solid defenses against the dark art of CSRF attacks!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3rnghmypieu8cuy2f8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3rnghmypieu8cuy2f8j.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this useful, check out &lt;a href="https://manning.com/books/elm-in-action?a_aid=elm_in_action&amp;amp;a_bid=b15edc5c" rel="noopener noreferrer"&gt;the book I'm writing for Manning Publications&lt;/a&gt;. I've put a ton of time and love into writing it!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>web</category>
      <category>csrf</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Where Should Tests Live?</title>
      <dc:creator>Richard Feldman</dc:creator>
      <pubDate>Mon, 20 Feb 2017 00:31:32 +0000</pubDate>
      <link>https://dev.to/rtfeldman/where-should-tests-live</link>
      <guid>https://dev.to/rtfeldman/where-should-tests-live</guid>
      <description>&lt;p&gt;I came across a design question when working on &lt;a href="https://github.com/elm-community/elm-test/"&gt;elm-test&lt;/a&gt; recently:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What if you could write tests in the same file as the code they're testing?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are a few testing systems that support this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://clojure.org/about/spec#_for_testing"&gt;&lt;code&gt;clojure.spec&lt;/code&gt;&lt;/a&gt; (to vastly oversimplify) &lt;a href="http://stackoverflow.com/questions/37942495/where-to-put-specs-for-clojure-spec"&gt;lets you define tests inline&lt;/a&gt; in the same file as your business logic.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.rust-lang.org/book/testing.html"&gt;Rust&lt;/a&gt; allows putting tests in the same file as the code being tested, although the documentation recommends putting them in a separate file (without elaboration as to why).&lt;/li&gt;
&lt;li&gt;Doctests (such as in &lt;a href="https://docs.python.org/2/library/doctest.html"&gt;Python&lt;/a&gt;, &lt;a href="http://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests"&gt;Elixir&lt;/a&gt;, &lt;a href="https://blog.golang.org/examples"&gt;Go&lt;/a&gt;, and &lt;a href="https://hackage.haskell.org/package/doctest"&gt;Haskell&lt;/a&gt;) allow writing tests in the same file—theoretically for documentation purposes, although potentially for testing purposes instead.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://erlang.org/doc/apps/eunit/chapter.html"&gt;&lt;code&gt;EUnit&lt;/code&gt;&lt;/a&gt; in Erlang runs all functions in a given module that end in &lt;code&gt;_test&lt;/code&gt; as tests, including business logic modules.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://groups.google.com/forum/#!topic/racket-users/awkxA9_Ye5I"&gt;Racket&lt;/a&gt; supports inline tests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pyret.org/docs/latest/testing.html"&gt;Pyret&lt;/a&gt; supports "testing blocks" which can live in any source file.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://search.cpan.org/~adamk/Test-Inline-2.213/lib/Test/Inline.pm"&gt;&lt;code&gt;Test::Inline&lt;/code&gt;&lt;/a&gt; adds support for this to Perl.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've never used any of these, but I'm wondering how the experience would be in practice. Is it amazing? Unexciting? An outright bad idea? What are the pros and cons compared to putting tests in a separate file?&lt;/p&gt;

&lt;p&gt;If you've tried writing tests like this before, what did you think?&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tests</category>
      <category>questions</category>
    </item>
    <item>
      <title>I am the author of Elm in Action. Ask Me Anything!</title>
      <dc:creator>Richard Feldman</dc:creator>
      <pubDate>Thu, 19 Jan 2017 18:24:15 +0000</pubDate>
      <link>https://dev.to/rtfeldman/i-am-the-author-of-elm-in-action-ask-me-anything</link>
      <guid>https://dev.to/rtfeldman/i-am-the-author-of-elm-in-action-ask-me-anything</guid>
      <description>&lt;p&gt;I am Richard Feldman, author of &lt;a href="https://www.manning.com/books/elm-in-action?a_aid=elm_in_action&amp;amp;a_bid=b15edc5c"&gt;Elm in Action&lt;/a&gt; and instructor of the &lt;a href="https://frontendmasters.com/workshops/elm/"&gt;Frontend Masters Elm Workshop&lt;/a&gt;. The main open-source projects I'm working on right now are &lt;a href="http://package.elm-lang.org/packages/elm-community/elm-test/latest"&gt;&lt;code&gt;elm-test&lt;/code&gt;&lt;/a&gt; and &lt;a href="http://package.elm-lang.org/packages/rtfeldman/elm-css/latest"&gt;&lt;code&gt;elm-css&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I work at &lt;a href="https://www.noredink.com/"&gt;NoRedInk&lt;/a&gt;, where we have 80,000 lines of &lt;a href="https://www.youtube.com/watch?v=FV0DXNB94NE"&gt;Elm code in production&lt;/a&gt;. We introduced &lt;a href="http://elm-lang.org/"&gt;Elm&lt;/a&gt; in 2015, and since then our production Elm code has thrown a total of zero runtime exceptions. &lt;a href="http://tech.noredink.com/post/136615783598/welcome-evan"&gt;We hired Elm creator Evan Czaplicki&lt;/a&gt; in 2015 to continue developing the language, and &lt;a href="http://noredink.com/jobs"&gt;we're hiring!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll be here until noon Pacific Time. Ask Me Anything!&lt;/p&gt;

</description>
      <category>ama</category>
    </item>
  </channel>
</rss>
