Skip to content

Instantly share code, notes, and snippets.

@BinaryMuse
Forked from evancz/Architecture.md
Created March 24, 2016 02:45
Show Gist options
  • Select an option

  • Save BinaryMuse/4ad1bbf8a97b9b5e49c9 to your computer and use it in GitHub Desktop.

Select an option

Save BinaryMuse/4ad1bbf8a97b9b5e49c9 to your computer and use it in GitHub Desktop.

Revisions

  1. @process-bot process-bot revised this gist Jul 21, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -39,7 +39,7 @@ When you have a ton of widgets, all with different sets of actions, how do you u

    ### Nesting

    So lets say we have three different widgets, each with their code living in modules called `SearchBar`, `Filters`, and `Results`. This means we have three sets of actions `SearchBar.Action`, `Filters.Action`, and `Results.Action` which we do not know anything about. To put them together, we would create some nested actions and state:
    So let's say we have three different widgets, each with their code living in modules called `SearchBar`, `Filters`, and `Results`. This means we have three sets of actions `SearchBar.Action`, `Filters.Action`, and `Results.Action` which we do not know anything about. To put them together, we would create some nested actions and state:

    ```haskell
    data Action
  2. @process-bot process-bot revised this gist Jul 19, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -143,7 +143,7 @@ It may also be a good idea to make input creation syntactic as with ports and to

    ## Focus

    It is possible to give widgets access to a small part of the overall state. Say you want the `Filters` widget to set some state relevant to the `SearchBox` widget. One way to do this is to have a `Filters.Action` that knows about that particular piece of state. You could handle that particular action one level above in the code that manages the many subcomponents.
    It is possible to give widgets access to a small part of the overall state. Say you want the `Filters` widget to set some state relevant to the `SearchBox` widget. One way to do this is to have a `Filters.Action` that knows about that particular piece of state. You could handle that particular action one level above in the code that manages the many subcomponents. I think this is fairly intuitive and will work well enough.

    A `Focus` generalizes this idea of giving access to a subpart of a big data structure. I have tried to [outline the idea](https://gist.github.com/evancz/78293dc6a4ac2547676c) as I think it should look in Elm, but I'm not sure it is actually a big win for architecting applications. It sounds promising, but it has a conceptual complexity cost that I'm not sure will pay off. My main concern is that, by making it easy to look deep inside of data structures, it encourages you to stop thinking about how to make these substructures modular, perhaps leading to an architecture that is not as nice *and* has extra conceptual complexity.

  3. @process-bot process-bot revised this gist Jul 19, 2014. 1 changed file with 29 additions and 2 deletions.
    31 changes: 29 additions & 2 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -97,6 +97,29 @@ This way you still have the structure of an ADT that helps organize code and for

    I am not sure how this approach will work out in practice as I personally favor ADTs, but I think we should explore it more and see how it goes. I can see it going either way.

    ### Reusable Actions

    So assuming we go with something like `type Action = State -> State`, how can we reuse an action on different kinds of state? Elm's [extensible records](http://elm-lang.org/learn/Records.elm) can help a lot with this. Rather than defining a totally opaque type `State`, we can build it from smaller pieces:

    ```haskell
    type Position r = { r | x:Float, y:Float }
    type Velocity r = { r | vx:Float, vy:Float }
    type Lives r = { r | lives:Int }
    type Coins r = { r | coins:Int }

    type Mario = Position (Velocity (Lives {}))
    type Goomba = Position (Velocity {})
    type Brick = Position (Coins {})

    oneUp : Lives r -> Lives r

    gravity : Time -> Position (Velocity r) -> Position (Velocity r)

    takeCoin : Coins r -> Coins r
    ```

    Now we can use the `oneUp` and `gravity` functions on anything that have the required fields. So stepping Mario's state forward could look like `oneUp . gravity dt`. This gives us an interesting way to reuse functions that may be more clever than is necessary in practice, but at least now you know it's available to you!

    ## Specializing Inputs

    This section is about conveniences that may need to be added to Elm to fully realize the vision outlined here.
    @@ -118,6 +141,10 @@ resultsInput = specialize Results appInput

    It may also be a good idea to make input creation syntactic as with ports and to demand that they all be created in the Main module to ensure that people structure their code in a reusable way.

    ## Potential Pitfalls
    ## Focus

    It is possible to give widgets access to a small part of the overall state. Say you want the `Filters` widget to set some state relevant to the `SearchBox` widget. One way to do this is to have a `Filters.Action` that knows about that particular piece of state. You could handle that particular action one level above in the code that manages the many subcomponents.

    A `Focus` generalizes this idea of giving access to a subpart of a big data structure. I have tried to [outline the idea](https://gist.github.com/evancz/78293dc6a4ac2547676c) as I think it should look in Elm, but I'm not sure it is actually a big win for architecting applications. It sounds promising, but it has a conceptual complexity cost that I'm not sure will pay off. My main concern is that, by making it easy to look deep inside of data structures, it encourages you to stop thinking about how to make these substructures modular, perhaps leading to an architecture that is not as nice *and* has extra conceptual complexity.

    In the Om library for ClojureScript, you are provided with a "cursor" which is kind of like a view into a small part of a big chunk of data. On its surface it sounds like a promising way to modularize things, but I am somewhat skeptical that this approach will win out in the long run. You can read more about this idea and the tradeoffs [here](https://gist.github.com/evancz/78293dc6a4ac2547676c).
    The reason for my skepticism is that I'd like to keep the number of new concepts as low as possible. If we can get by without this, I think Elm will be more attractive.
  4. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ In Elm you have the added benefit that these abstraction boundaries are quite st

    ## Extensibility

    When you have a ton of widgets, all with different sets of actions, how do you use them all together? You cannot have one giant [ADT](http://elm-lang.org/learn/Pattern-Matching.elm). There are a few techniques here.
    When you have a ton of widgets, all with different sets of actions, how do you use them all together? [The TodoMVC code](https://github.com/evancz/elm-todomvc/blob/master/Todo.elm) uses a big ADT called `Action`, but that is not easy to extend. There are a few useful techniques here.

    ### Nesting

  5. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 22 additions and 5 deletions.
    27 changes: 22 additions & 5 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,26 @@ You can just keep nesting and nesting like this. For example, the `Results` modu

    ### Generalizing Actions

    In some cases where you want an ADT to be more extensible, it may be good to include one case that is fully general:
    In some cases where you want an ADT to be more extensible. Here is the fully general approach:

    ```haskell
    type Action = State -> State

    removeTask : Int -> Action
    removeTask id state =
    { state | tasks <- filter (\task -> task.id /= id) state.tasks }
    ```

    We can then expose a set of functions like `removeTask` that let people create a certain set of `Actions`. So rather than having a step function that handles the many cases of an ADT, we just apply the `Action` to the state:

    ```haskell
    step : Action -> State -> State
    step action state = action state
    ```

    It is just function application! This means people can write their own functions like `(resize : Int -> Int -> State -> State)` just by building up from the publicly available ways to transition state. This means we can act on `State` in composable ways without revealing any facts about `State`.

    This can also be mixed with the ADT approach like so:

    ```haskell
    data Action
    @@ -74,11 +93,9 @@ data Action
    | Anything (State -> State)
    ```

    Notice that the `Anything` constructor lets you specify an arbitrary way to update the state. This means anyone can do anything at any time. That certainly makes things extensible, but I suspect this is not such a great idea without some restrictions.

    Perhaps instead of exposing all internal state, you can expose a function that only has access to the parts you want people to know about. Something like `Anything (String -> String) (Int -> Int)` so you can only transition certain parts of your `State`. Another approach is to provide some functions like `(resize : Int -> Int -> State -> State)` but not reveal any facts about `State`.
    This way you still have the structure of an ADT that helps organize code and forces you to think hard about what functionality you actually want, but you can escape that structure if needed using the `Anything` case which will just step the state in an arbitrary way.

    I'm less confident that this will work out great, but I think it should be explored further. I can see it going either way.
    I am not sure how this approach will work out in practice as I personally favor ADTs, but I think we should explore it more and see how it goes. I can see it going either way.

    ## Specializing Inputs

  6. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ This document is a collection of concepts and strategies to make large Elm proje

    We will start by thinking about the structure of signals in our program. Broadly speaking, your application state should live in one big `foldp`. You will probably `merge` a bunch of input signals into a single stream of updates. This sounds a bit crazy at first, but it is in the same ballpark as Om or Facebook's Flux. There are a couple major benefits to having a centralized home for your application state:

    1. **There is a single source of truth.** Traditional approaches force you to write a decent amount of custom and error prone code to synchronize state between many different stateful components. (The state of this widget needs to be synced with the application state, which needs to be synced with some other widget, etc.) By placing all of your state in one location, you eliminate an entire class of bugs in which two components get into inconsistent states. We also think you will end up writing much less code, at least, that has been our observation in Elm so far.
    1. **There is a single source of truth.** Traditional approaches force you to write a decent amount of custom and error prone code to synchronize state between many different stateful components. (The state of this widget needs to be synced with the application state, which needs to be synced with some other widget, etc.) By placing all of your state in one location, you eliminate an entire class of bugs in which two components get into inconsistent states. We also think you will end up writing much less code. That has been our observation in Elm so far.

    2. **Save and Undo become quite easy.** Many applications would benefit from the ability to save all application state and send it off to the server so it can be reloaded at some later date. This is extremely difficult when your application state is spread all over the place and potentially tied to objects that cannot be serialized. With a central store, this becomes very simple. Many applications would also benefit from the ability to easily undo user's actions. For example, a painting app is better with Undo. Since everything is immutable in Elm, this is also very easy. Saving past states is trivial, and you will automatically get pretty good sharing guarantees to keep the size of the snapshots down.

  7. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # Architecture in Elm

    This document is a collection of concepts and strategies to make your Elm projects modular and extensible.
    This document is a collection of concepts and strategies to make large Elm projects modular and extensible.

    We will start by thinking about the structure of signals in our program. Broadly speaking, your application state should live in one big `foldp`. You will probably `merge` a bunch of input signals into a single stream of updates. This sounds a bit crazy at first, but it is in the same ballpark as Om or Facebook's Flux. There are a couple major benefits to having a centralized home for your application state:

  8. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Architecture.md
    Original file line number Diff line number Diff line change
    @@ -103,4 +103,4 @@ It may also be a good idea to make input creation syntactic as with ports and to

    ## Potential Pitfalls

    In the Om library for ClojureScript, you are provided with a "cursor" which is kind of like a view into a small part of a big chunk of data. On its surface it sounds like a promising way to modularize things, but I am somewhat skeptical that this approach will win out in the long run. You can read more about this idea [here](https://gist.github.com/evancz/78293dc6a4ac2547676c).
    In the Om library for ClojureScript, you are provided with a "cursor" which is kind of like a view into a small part of a big chunk of data. On its surface it sounds like a promising way to modularize things, but I am somewhat skeptical that this approach will win out in the long run. You can read more about this idea and the tradeoffs [here](https://gist.github.com/evancz/78293dc6a4ac2547676c).
  9. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 30 additions and 12 deletions.
    42 changes: 30 additions & 12 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -39,50 +39,68 @@ When you have a ton of widgets, all with different sets of actions, how do you u

    ### Nesting

    So lets say we have three different widgets, each with their code living in modules called `SearchBar`, `Filters`, and `Results`. This means we have three sets of actions `SearchBar.Action`, `Filters.Action`, and `Results.Action` which we do not know anything about. To put them together, we would create a meta action:
    So lets say we have three different widgets, each with their code living in modules called `SearchBar`, `Filters`, and `Results`. This means we have three sets of actions `SearchBar.Action`, `Filters.Action`, and `Results.Action` which we do not know anything about. To put them together, we would create some nested actions and state:

    ```elm
    ```haskell
    data Action
    = SearchBar SearchBar.Action
    | Filters Filters.Action
    | Results Results.Action

    type State =
    { searchBar : SearchBar.State
    , filters : Filters.State
    , results : Results.State
    }

    step : Action -> State -> State
    step action state =
    case action of
    SearchBar a -> SearchBar.step a state.searchBar
    Filters a -> Filters.step a state.filters
    Results a -> Results.step a state.results
    SearchBar a -> { state | searchBar <- SearchBar.step a state.searchBar }
    Filters a -> { state | filters <- Filters.step a state.filters }
    Results a -> { state | results <- Results.step a state.results }
    ```

    You can just keep nesting and nesting ADTs like this. For example the Results module may be made up of 4 smaller ones and we don't need to know anything about that.
    You can just keep nesting and nesting like this. For example, the `Results` module may be made up of 4 smaller widgets with their own actions and state and we don't need to know anything about those details.

    ### Generalizing Actions

    In some cases where you want an ADT to be more extensible, it may be good to include one case that is fully general:

    ```haskell
    data Action
    = RemoveTask Int
    | ...
    | Anything (State -> State)
    ```

    I suspect this is not such a great idea in practice, but if you need to make your widget extensible to outsiders, some variation of this may be nice. Perhaps instead of exposing all internal state, you can expose a function that only has access to the parts you want people to know about. Or not expose any details about State and just provide some functions like (resize : Int -> Int -> State -> State).
    Notice that the `Anything` constructor lets you specify an arbitrary way to update the state. This means anyone can do anything at any time. That certainly makes things extensible, but I suspect this is not such a great idea without some restrictions.

    I'm less confident that this will be great, but I do think it should be explored. I can see it going either way.
    Perhaps instead of exposing all internal state, you can expose a function that only has access to the parts you want people to know about. Something like `Anything (String -> String) (Int -> Int)` so you can only transition certain parts of your `State`. Another approach is to provide some functions like `(resize : Int -> Int -> State -> State)` but not reveal any facts about `State`.

    There are a couple other techniques, but I have thought about them less and will save them for later.
    I'm less confident that this will work out great, but I think it should be explored further. I can see it going either way.

    ## Specializing Inputs

    This section is about conveniences that may need to be added to Elm to fully realize the vision outlined here.

    I think it may be pleasant/necessary to introduce a function something like this:

    ```haskell
    specialize : (particular -> general) -> Input general -> Input particular
    ```

    The idea is that you can create one input, but have all 3 of your widgets report to it with things like this:
    Notice that the order of arguments seems a bit wonky here. You are creating a new input of `particulars` and you need a way to convert all of those to the more `general` type to integrate with the rest of the system. The idea is that you can create one input, but have all 3 of your widgets report to it with things like this:

    ```haskell
    -- using the general Action ADT defined earlier
    searchBarInput = specialize SearchBar appInput
    filtersInput = specialize Filters appInput
    resultsInput = specialize Results appInput
    filtersInput = specialize Filters appInput
    resultsInput = specialize Results appInput
    ```

    It may also be a good idea to make input creation syntactic as with ports and to demand that they all be created in the Main module to ensure that people structure their code in a reusable way.

    ## Potential Pitfalls

    In the Om library for ClojureScript, you are provided with a "cursor" which is kind of like a view into a small part of a big chunk of data. On its surface it sounds like a promising way to modularize things, but I am somewhat skeptical that this approach will win out in the long run. You can read more about this idea [here](https://gist.github.com/evancz/78293dc6a4ac2547676c).
  10. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    This document is a collection of concepts and strategies to make your Elm projects modular and extensible.

    We will start by thinking about the structure of signals in our program. Broadly speaking, your application state should live in one big `foldp`. You will probably `merge` a bunch of input signals into a single stream of updates. This sounds a bit crazy at first, but it is in the same ballpark as Om or Facebook&rsquo;s Flux. There are a couple major benefits to having a centralized home for your application state:
    We will start by thinking about the structure of signals in our program. Broadly speaking, your application state should live in one big `foldp`. You will probably `merge` a bunch of input signals into a single stream of updates. This sounds a bit crazy at first, but it is in the same ballpark as Om or Facebook's Flux. There are a couple major benefits to having a centralized home for your application state:

    1. **There is a single source of truth.** Traditional approaches force you to write a decent amount of custom and error prone code to synchronize state between many different stateful components. (The state of this widget needs to be synced with the application state, which needs to be synced with some other widget, etc.) By placing all of your state in one location, you eliminate an entire class of bugs in which two components get into inconsistent states. We also think you will end up writing much less code, at least, that has been our observation in Elm so far.

    @@ -31,7 +31,9 @@ View.mini : Input Action -> State -> Element

    As a user, you don't know anything about what `State` really is, but you have carefully selected functions for creating it, stepping it, and doing custom modifications without an Action (e.g. `resetField`) in case other components need to act on the state. The designer has full control over the API they expose and can hide any details they want.

    ## Extensiblity
    In Elm you have the added benefit that these abstraction boundaries are quite strong. Unlike in JS, you cannot just inspect the structure of arbitrary values and do what you want with that. That means best practices must be enforced with culture or dogma. In Elm you can actually ensure that people write code in a good way.

    ## Extensibility

    When you have a ton of widgets, all with different sets of actions, how do you use them all together? You cannot have one giant [ADT](http://elm-lang.org/learn/Pattern-Matching.elm). There are a few techniques here.

  11. @process-bot process-bot revised this gist Jul 18, 2014. 1 changed file with 13 additions and 14 deletions.
    27 changes: 13 additions & 14 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,16 @@
    # Notes on Architecture

    And when you create the combined view, you have access to all the data from everywhere if you want. One benefit of this is that there is a single source of truth in your application. When you update a value, all views are guaranteed to be synced. I think this will be a powerful guarantee!

    The general approach is in the same ballpark as architecting large applications
    with Om or Facebook&rsquo;s Flux. There are a couple major benefits of these
    approaches that I'll outline briefly. First, this means there is no need to
    synchronize state between many different stateful components. This eliminates
    an entire class of bugs in which two components get into inconsistent states.
    Second, it makes it much easier to implement undo because you can easily
    snapshot the entire state of your application at any moment, though this is
    much more reliable with purity and immutability. I think these strengths will
    be extremely worthwhile in large applications, and I will try to address this
    more fully in a future post.
    # Architecture in Elm

    This document is a collection of concepts and strategies to make your Elm projects modular and extensible.

    We will start by thinking about the structure of signals in our program. Broadly speaking, your application state should live in one big `foldp`. You will probably `merge` a bunch of input signals into a single stream of updates. This sounds a bit crazy at first, but it is in the same ballpark as Om or Facebook&rsquo;s Flux. There are a couple major benefits to having a centralized home for your application state:

    1. **There is a single source of truth.** Traditional approaches force you to write a decent amount of custom and error prone code to synchronize state between many different stateful components. (The state of this widget needs to be synced with the application state, which needs to be synced with some other widget, etc.) By placing all of your state in one location, you eliminate an entire class of bugs in which two components get into inconsistent states. We also think you will end up writing much less code, at least, that has been our observation in Elm so far.

    2. **Save and Undo become quite easy.** Many applications would benefit from the ability to save all application state and send it off to the server so it can be reloaded at some later date. This is extremely difficult when your application state is spread all over the place and potentially tied to objects that cannot be serialized. With a central store, this becomes very simple. Many applications would also benefit from the ability to easily undo user's actions. For example, a painting app is better with Undo. Since everything is immutable in Elm, this is also very easy. Saving past states is trivial, and you will automatically get pretty good sharing guarantees to keep the size of the snapshots down.

    I think these two strengths will be extremely worthwhile in large applications, though I feel that strength 1 is a huge deal for speeding up development and avoiding silly bugs that waste your time.

    So most of your code will be pure functions that make your big `foldp` actually do the right thing. The rest of this document focuses on how to make *that* code modular and extensible.

    ## Modularity

  12. @process-bot process-bot created this gist Jul 18, 2014.
    87 changes: 87 additions & 0 deletions Architecture.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    # Notes on Architecture

    And when you create the combined view, you have access to all the data from everywhere if you want. One benefit of this is that there is a single source of truth in your application. When you update a value, all views are guaranteed to be synced. I think this will be a powerful guarantee!

    The general approach is in the same ballpark as architecting large applications
    with Om or Facebook&rsquo;s Flux. There are a couple major benefits of these
    approaches that I'll outline briefly. First, this means there is no need to
    synchronize state between many different stateful components. This eliminates
    an entire class of bugs in which two components get into inconsistent states.
    Second, it makes it much easier to implement undo because you can easily
    snapshot the entire state of your application at any moment, though this is
    much more reliable with purity and immutability. I think these strengths will
    be extremely worthwhile in large applications, and I will try to address this
    more fully in a future post.

    ## Modularity

    To make things modular, the major strategy is to hide implementation details, as shown in [this pseudocode](https://gist.github.com/evancz/ee696a87a644a3d1fa02). When you create a widget, this makes it possible to expose exactly the API you want. Essentially just this kind of info:

    ```haskell
    type Model.State
    type Model.Action

    Model.initialize : String -> ... -> State

    Update.step : Action -> State -> State
    Update.resetField : State -> State

    View.full : Input Action -> State -> Element
    View.mini : Input Action -> State -> Element
    ```

    As a user, you don't know anything about what `State` really is, but you have carefully selected functions for creating it, stepping it, and doing custom modifications without an Action (e.g. `resetField`) in case other components need to act on the state. The designer has full control over the API they expose and can hide any details they want.

    ## Extensiblity

    When you have a ton of widgets, all with different sets of actions, how do you use them all together? You cannot have one giant [ADT](http://elm-lang.org/learn/Pattern-Matching.elm). There are a few techniques here.

    ### Nesting

    So lets say we have three different widgets, each with their code living in modules called `SearchBar`, `Filters`, and `Results`. This means we have three sets of actions `SearchBar.Action`, `Filters.Action`, and `Results.Action` which we do not know anything about. To put them together, we would create a meta action:

    ```elm
    data Action
    = SearchBar SearchBar.Action
    | Filters Filters.Action
    | Results Results.Action

    step : Action -> State -> State
    step action state =
    case action of
    SearchBar a -> SearchBar.step a state.searchBar
    Filters a -> Filters.step a state.filters
    Results a -> Results.step a state.results
    ```

    You can just keep nesting and nesting ADTs like this. For example the Results module may be made up of 4 smaller ones and we don't need to know anything about that.

    ### Generalizing Actions

    In some cases where you want an ADT to be more extensible, it may be good to include one case that is fully general:

    data Action
    = RemoveTask Int
    | ...
    | Anything (State -> State)

    I suspect this is not such a great idea in practice, but if you need to make your widget extensible to outsiders, some variation of this may be nice. Perhaps instead of exposing all internal state, you can expose a function that only has access to the parts you want people to know about. Or not expose any details about State and just provide some functions like (resize : Int -> Int -> State -> State).

    I'm less confident that this will be great, but I do think it should be explored. I can see it going either way.

    There are a couple other techniques, but I have thought about them less and will save them for later.

    ## Specializing Inputs

    I think it may be pleasant/necessary to introduce a function something like this:

    specialize : (particular -> general) -> Input general -> Input particular

    The idea is that you can create one input, but have all 3 of your widgets report to it with things like this:

    searchBarInput = specialize SearchBar appInput
    filtersInput = specialize Filters appInput
    resultsInput = specialize Results appInput

    It may also be a good idea to make input creation syntactic as with ports and to demand that they all be created in the Main module to ensure that people structure their code in a reusable way.