├── .gitignore ├── backend └── elixir │ ├── gen_server │ ├── kv │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ ├── kv_test.exs │ │ │ ├── bucket_test.exs │ │ │ └── registry_test.exs │ │ ├── lib │ │ │ ├── kv.ex │ │ │ └── kv │ │ │ │ ├── supervisor.ex │ │ │ │ ├── bucket.ex │ │ │ │ ├── bucket │ │ │ │ └── supervisor.ex │ │ │ │ └── registry.ex │ │ ├── .gitignore │ │ ├── README.md │ │ ├── mix.exs │ │ └── config │ │ │ └── config.exs │ ├── stack.exs │ ├── kv_registry.exs │ └── stack_improved.exs │ ├── pragmatic-elixir │ ├── projects │ │ └── issues │ │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ ├── issues_test.exs │ │ │ └── cli_test.exs │ │ │ ├── lib │ │ │ ├── issues.ex │ │ │ └── issues │ │ │ │ ├── github_issues.ex │ │ │ │ ├── table_formatter.ex │ │ │ │ └── cli.ex │ │ │ ├── issues │ │ │ ├── config │ │ │ └── config.exs │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── mix.exs │ │ │ └── mix.lock │ ├── chapter-8-dictionaries │ │ ├── keyword-list.exs │ │ ├── sets.exs │ │ └── maps.exs │ ├── chapter-8-maps │ │ └── sets.exs │ ├── chapter-14-processes │ │ ├── README.md │ │ ├── parallel-map.exs │ │ ├── chain.exs │ │ ├── spawn-basic.exs │ │ └── fibonacci.exs │ ├── chapter-7-lists │ │ ├── challenges.ex │ │ ├── operations.exs │ │ ├── notes.md │ │ ├── complex-lists.exs │ │ └── lists.exs │ ├── modules_and_functions.exs │ └── chapter-10-collections │ │ └── enum.exs │ ├── processes │ ├── spawn-link.exs │ ├── agents.exs │ ├── state.exs │ ├── task.exs │ └── spawn.exs │ ├── workshops │ └── elixir_express │ │ ├── README.md │ │ ├── examples │ │ ├── fibonacci.exs │ │ ├── process_example.exs │ │ ├── rocket.exs │ │ └── counter.exs │ │ └── notes │ │ ├── pipeline-operator.md │ │ ├── control-flow.md │ │ └── basics.md │ ├── README.md │ ├── fs │ └── io.exs │ ├── enumerables-and-streams │ └── README.md │ ├── ecto │ └── README.md │ ├── elixir-in-action │ ├── database_server.exs │ └── calculator.exs │ ├── gen_server.md │ ├── basics.md │ └── concurrency.md ├── README.md ├── design ├── research │ ├── research-method.png │ └── research.md ├── README.md ├── the-facebook-habit.md ├── design-and-choice.md ├── designing-for-wide-walls.md └── the-lessons-of-good-design.md ├── product-management ├── resources │ ├── Shipping Features.png │ ├── Feature Usage Chart.png │ ├── Product Trial Goals.png │ ├── Iterate On Possible Conclusions.png │ └── Feature Usage Chart Prioritization.png ├── podcasts.md └── videos.md ├── front-end ├── performance │ └── talks.md └── frameworks │ ├── angular │ ├── RESOURCES.md │ └── README.md │ └── react │ ├── renderers │ ├── shared │ │ ├── shared │ │ │ └── getContextForSubtree.md │ │ └── fiber │ │ │ ├── ReactFiberRoot.md │ │ │ ├── ReactFiberUpdateQueue.md │ │ │ ├── ReactFiberReconciler.md │ │ │ ├── ReactFiber.md │ │ │ └── createContainer.md │ └── noop │ │ └── README.md │ └── README.md ├── interview └── trees │ └── traversal.md ├── editors └── playlist.md ├── data-science └── engineering │ └── kafka.md ├── type-systems ├── hindley-milner.md ├── resources.md ├── README.md └── flow-intro.md ├── ocaml ├── cheatsheet.md └── README.md ├── writing └── ideas.md ├── computer-science └── history.md ├── database └── redis │ └── README.md ├── life └── Ten Lessons I wish I had been Taught.md └── agile └── frankenbuilds.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore OS specific files 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | end 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | A collection of notes and resources used for understanding and teaching concepts. 4 | -------------------------------------------------------------------------------- /design/research/research-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/design/research/research-method.png -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-8-dictionaries/keyword-list.exs: -------------------------------------------------------------------------------- 1 | # Keyword Lists 2 | kwlist = [bg: "black", fg: "white"] 3 | kwlist[:bg] 4 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | end 5 | -------------------------------------------------------------------------------- /backend/elixir/processes/spawn-link.exs: -------------------------------------------------------------------------------- 1 | spawn_link fn -> raise "oops" end 2 | 3 | receive do 4 | :hello -> "let's wait until the process fails" 5 | end 6 | -------------------------------------------------------------------------------- /product-management/resources/Shipping Features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/product-management/resources/Shipping Features.png -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/issues: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/backend/elixir/pragmatic-elixir/projects/issues/issues -------------------------------------------------------------------------------- /product-management/resources/Feature Usage Chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/product-management/resources/Feature Usage Chart.png -------------------------------------------------------------------------------- /product-management/resources/Product Trial Goals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/product-management/resources/Product Trial Goals.png -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/lib/kv.ex: -------------------------------------------------------------------------------- 1 | defmodule KV do 2 | use Application 3 | 4 | def start(_type, _args) do 5 | KV.Supervisor.start_link 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/README.md: -------------------------------------------------------------------------------- 1 | ## All Aboard The Elixir Express! by Chris McCord 2 | 3 | Source: [Link](https://www.youtube.com/watch?v=5kYmOyJjGDM) 4 | -------------------------------------------------------------------------------- /design/README.md: -------------------------------------------------------------------------------- 1 | # Design 2 | 3 | A collection of design topics and resources. 4 | 5 | ## Podcasts 6 | 7 | - [Invisible Unicorns](https://designdetails.simplecast.fm/172) 8 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/test/kv_test.exs: -------------------------------------------------------------------------------- 1 | defmodule KVTest do 2 | use ExUnit.Case 3 | doctest KV 4 | 5 | test "the truth" do 6 | assert 1 + 1 == 2 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /product-management/resources/Iterate On Possible Conclusions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/product-management/resources/Iterate On Possible Conclusions.png -------------------------------------------------------------------------------- /product-management/resources/Feature Usage Chart Prioritization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshblack/notes-old/HEAD/product-management/resources/Feature Usage Chart Prioritization.png -------------------------------------------------------------------------------- /front-end/performance/talks.md: -------------------------------------------------------------------------------- 1 | # Performance Talks 2 | 3 | ## Windowing 4 | 5 | - [Creating more efficient React views with windowing](https://www.youtube.com/watch?v=t4tuhg7b50I) by Brian Vaughn 6 | -------------------------------------------------------------------------------- /backend/elixir/processes/agents.exs: -------------------------------------------------------------------------------- 1 | {:ok, pid} = Agent.start_link(fn -> %{} end) 2 | 3 | Agent.update(pid, fn map -> Map.put(map, :hello, :world) end) 4 | 5 | Agent.get(pid, fn map -> Map.get(map, :hello) end) 6 | -------------------------------------------------------------------------------- /interview/trees/traversal.md: -------------------------------------------------------------------------------- 1 | ## Tree Traversals 2 | 3 | - In-Order Traversal: used to go through a BST in order from smallest to largest element in the three 4 | - Pre-Order Traversal 5 | - Post-Order Traversal 6 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/examples/fibonacci.exs: -------------------------------------------------------------------------------- 1 | defmodule Fibonacci do 2 | def value(0), do: 0 3 | def value(1), do: 1 4 | def value(term) when term >= 0 do 5 | value(term - 1) + value(term - 2) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /editors/playlist.md: -------------------------------------------------------------------------------- 1 | # Vim Playlist 2 | 3 | > A collection of useful videos for Vim + Tmux 4 | 5 | - [Impressive Ruby Productivity with Vim and Tmux](https://www.youtube.com/watch?v=9jzWDr24UHQ) 6 | - [How to do 90% of what Plugins do with Vim](https://www.youtube.com/watch?v=XA2WjJbmmoM) 7 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | config :issues, github_url: "https://api.github.com" 6 | config :logger, compile_time_purge_level: :info 7 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/examples/process_example.exs: -------------------------------------------------------------------------------- 1 | pid = spawn fn -> 2 | receive do 3 | {sender, :ping} -> 4 | IO.puts "Got ping" 5 | send sender, :pong 6 | end 7 | end 8 | 9 | send pid, {self, :ping} 10 | 11 | receive do 12 | message -> IO.puts "Got #{message} back" 13 | end 14 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-8-maps/sets.exs: -------------------------------------------------------------------------------- 1 | set1 = MapSet.new [1, 2, 3] 2 | set2 = MapSet.new [3, 4, 5, 6] 3 | 4 | MapSet.member? set1, 3 # true 5 | MapSet.member? set1, 5 # false 6 | 7 | union = MapSet.union set1, set2 8 | diff = MapSet.difference set1, set2 9 | intersect = MapSet.intersection set1, set2 10 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-8-dictionaries/sets.exs: -------------------------------------------------------------------------------- 1 | set1 = MapSet.new [1, 2, 3] 2 | set2 = MapSet.new [3, 4, 5, 6] 3 | 4 | MapSet.member? set1, 3 # true 5 | MapSet.member? set1, 5 # false 6 | 7 | union = MapSet.union set1, set2 8 | diff = MapSet.difference set1, set2 9 | intersect = MapSet.intersection set1, set2 10 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-14-processes/README.md: -------------------------------------------------------------------------------- 1 | # Working with Multiple Processes 2 | 3 | Elixir uses the _actor_ model of concurrency. In it, an actor is an independent process that shares nothing with any other process. 4 | 5 | You're allowed to _spawn_ new processes, _send_ them messages, and _receive_ messages back. And that's it! (apart from error-handling and monitoring) 6 | -------------------------------------------------------------------------------- /backend/elixir/processes/state.exs: -------------------------------------------------------------------------------- 1 | defmodule KV do 2 | def start_link do 3 | Task.start_link(fn -> loop(%{}) end) 4 | end 5 | 6 | defp loop(map) do 7 | receive do 8 | {:get, key, caller} -> 9 | send caller, Map.get(map, key) 10 | loop(map) 11 | {:put, key, value} -> 12 | loop(Map.put(map, key, value)) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-7-lists/challenges.ex: -------------------------------------------------------------------------------- 1 | defmodule MyList 2 | # Lists and Recursion - 1 3 | # mapsum : (list, func) :: number 4 | def mapsum([], _func), do: 0 5 | def mapsum([head | tail], func), do: func.(head) + mapsum(tail, func) 6 | 7 | # Lists and Recursion - 2 8 | def max([a]), do: a 9 | def max([head | tail]), do: Kernel.max(head, max(tail)) 10 | end 11 | -------------------------------------------------------------------------------- /backend/elixir/processes/task.exs: -------------------------------------------------------------------------------- 1 | # Tasks build on top of the spawn functions to provider error 2 | # reports and introspection 3 | 4 | # Task.start/1, Task.start_link/1 :: {:ok, pid} 5 | Task.start fn -> raise "oops" end 6 | 7 | # We can use tasks to return the {:ok, pid} tuple rather than just 8 | # the PID. This lets us use Tasks in supervision trees. 9 | 10 | # Task.async/1 and Task.await/1 11 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-14-processes/parallel-map.exs: -------------------------------------------------------------------------------- 1 | defmodule Parallel do 2 | def parallel_map(collection, func) do 3 | me = self 4 | 5 | collection 6 | |> Enum.map(fn (elem) -> 7 | spawn_link fn -> (send me, { self, func.(elem) }) end 8 | end) 9 | |> Enum.map(fn (pid) -> 10 | receive do { ^pid, result } -> result end 11 | end) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /data-science/engineering/kafka.md: -------------------------------------------------------------------------------- 1 | # Kafka 2 | 3 | > A distributed replicated log 4 | 5 | ## Topics and Partitions 6 | 7 | A topic is a logical grouping of partitions. A partition is just a log file. Kafka is append-only, so each new partition for a topic is appending to the end of the log. 8 | 9 | ## Resources 10 | 11 | - [Developing Real-Time Data Pipelines with Apache Kafka](https://www.youtube.com/watch?v=GRPLRONVDWY) 12 | -------------------------------------------------------------------------------- /type-systems/hindley-milner.md: -------------------------------------------------------------------------------- 1 | ## Hindley-Milner 2 | 3 | > An algorithm for inferring value types based on use. It literally formalizes the intuition that a type can be deduced by the functionality it supports. 4 | 5 | It looks through the body of a function and computes a constraint set based on how each value is used. Once it has the constraint set, the algorithm completes the type reconstruction by unifying the constraints. 6 | 7 | -------------------------------------------------------------------------------- /design/the-facebook-habit.md: -------------------------------------------------------------------------------- 1 | ## Habit Summit | The Facebook Habit: A Fireside Chat | Julie Zhou 2 | 3 | > Video Link: https://www.youtube.com/watch?v=gmvxtOSPYso 4 | 5 | ### Outline 6 | 7 | _15:51_ 8 | 9 | I think those are probably the two most habits for designer. 10 | 11 | - Share your work, early and often 12 | - Start projects by sitting down and having a little bit of time to think through the intentionality of the problem 13 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/modules_and_functions.exs: -------------------------------------------------------------------------------- 1 | # Convert a float to a string with two decimal digits 2 | :io.format("~.2~n", [2.0/3.0]) 3 | 4 | # Get the value of an OS env variable 5 | System.get_env("HOME") 6 | 7 | # REturn the extension-component of a file name 8 | Path.extname("modules_and_functions.exs") 9 | 10 | # Return the cwd 11 | System.cwd 12 | 13 | # Execute a command in your OS's shell 14 | System.cmd("date") 15 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/test/bucket_test.exs: -------------------------------------------------------------------------------- 1 | defmodule KV.BucketTest do 2 | use ExUnit.Case, async: true 3 | 4 | setup do 5 | {:ok, bucket} = KV.Bucket.start_link 6 | {:ok, bucket: bucket} 7 | end 8 | 9 | test "stores values by key", %{bucket: bucket} do 10 | assert KV.Bucket.get(bucket, "milk") == nil 11 | 12 | KV.Bucket.put(bucket, "milk", 3) 13 | assert KV.Bucket.get(bucket, "milk") == 3 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/notes/pipeline-operator.md: -------------------------------------------------------------------------------- 1 | ## Pipeline Operator 2 | 3 | ```ex 4 | "Hello" |> IO.puts 5 | 6 | [3, 6, 9] |> Enum.map(fn x -> x * 2 end) |> Enum.at(2) 7 | ``` 8 | 9 | Basically this is good because instead of having to do function composition with the notation `f(g(x))`, you do: `g(x) -> f(*g(x) result)` 10 | 11 | So you can read what the transformation flow is instead of having to read inside-out. 12 | 13 | -------------------------------------------------------------------------------- /ocaml/cheatsheet.md: -------------------------------------------------------------------------------- 1 | ## String 2 | 3 | ### Length 4 | 5 | ```ml 6 | String.length "Foo" 7 | ``` 8 | 9 | ## List 10 | 11 | ### Length 12 | 13 | ```ml 14 | let languages = ["OCaml";"Perl";"C"];; 15 | List.length languages 16 | ``` 17 | 18 | ### Map 19 | 20 | ```ml 21 | let languages = ["OCaml";"Perl";"C"];; 22 | List.map languages ~f:String.length 23 | 24 | (* Here, ~f is a labelled argument *) 25 | List.map ~f:String.length languages 26 | ``` 27 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-7-lists/operations.exs: -------------------------------------------------------------------------------- 1 | # List Operations 2 | [1, 2, 3] ++ [4, 5, 6] 3 | 4 | # Flatten 5 | List.flatten([[1], [2], [[3, 4]]]) 6 | 7 | # Fold (reduce) 8 | List.foldl([1, 2, 3], 0, fn value, acc -> value + acc end) 9 | List.foldr([1, 2, 3], 0, fn value, acc -> value + acc end) 10 | 11 | # List.keyfind(list, value, index) 12 | # List.keydelete(kw, "TX", 1, "Default Message") 13 | # List.keyreplace(kw, value, index, replacement) 14 | -------------------------------------------------------------------------------- /writing/ideas.md: -------------------------------------------------------------------------------- 1 | # Ideas (2017) 2 | 3 | - Engineering 4 | - GraphQL 5 | - GraphQL Schema organization in Elixir/Absinthe 6 | - Elixir, Phoenix, and Docker 7 | - Elixir 8 | - Using ExMachina for Database Seeding 9 | - Testing 10 | - Jest + Nightmare with Nightmare and Docker (in CI environments) 11 | - React 12 | - Using StaggeredMotion for animating collections 13 | - Relay 14 | - Understanding `RANGE_ADD` 15 | - Design 16 | - Product 17 | - Career 18 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/lib/kv/supervisor.ex: -------------------------------------------------------------------------------- 1 | defmodule KV.Supervisor do 2 | use Supervisor 3 | 4 | def start_link do 5 | Supervisor.start_link(__MODULE__, :ok) 6 | end 7 | 8 | def init(:ok) do 9 | children = [ 10 | # Starts a process using the call: KV.Registry.start_link(KV.Registry) 11 | worker(KV.Registry, [KV.Registry]), 12 | supervisor(KV.Bucket.Supervisor, []) 13 | ] 14 | 15 | supervise(children, strategy: :rest_for_one) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/examples/rocket.exs: -------------------------------------------------------------------------------- 1 | defmodule Rocket do 2 | def start_launch_sequence(from \\ 10) when from >= 0 and from < 20 do 3 | IO.puts "Liftoff in #{from}..." 4 | countdown(from) 5 | end 6 | 7 | defp countdown(0), do: blastoff 8 | defp countdown(seconds) when is_integer seconds do 9 | IO.puts seconds 10 | countdown(seconds - 1) 11 | end 12 | 13 | def blastoff do 14 | IO.puts "Liftoff!" 15 | end 16 | end 17 | 18 | Rocket.start_launch_sequence 19 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc 12 | 13 | # If the VM crashes, it generates a dump, let's ignore it too. 14 | erl_crash.dump 15 | 16 | # Also ignore archive artifacts (built via "mix archive.build"). 17 | *.ez 18 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/README.md: -------------------------------------------------------------------------------- 1 | # Kv 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed as: 8 | 9 | 1. Add `kv` to your list of dependencies in `mix.exs`: 10 | 11 | ```elixir 12 | def deps do 13 | [{:kv, "~> 0.1.0"}] 14 | end 15 | ``` 16 | 17 | 2. Ensure `kv` is started before your application: 18 | 19 | ```elixir 20 | def application do 21 | [applications: [:kv]] 22 | end 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc 12 | 13 | # If the VM crashes, it generates a dump, let's ignore it too. 14 | erl_crash.dump 15 | 16 | # Also ignore archive artifacts (built via "mix archive.build"). 17 | *.ez 18 | -------------------------------------------------------------------------------- /backend/elixir/README.md: -------------------------------------------------------------------------------- 1 | ## Elixir 2 | 3 | ### Links & Resources 4 | 5 | #### Learning 6 | 7 | - [Awesome Elixir](https://github.com/h4cc/awesome-elixir#algorithms-and-data-structures) 8 | 9 | #### Walkthroughs 10 | 11 | - [Trello Clone with Phoenix and React](https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-1) 12 | 13 | #### Testing 14 | 15 | - [Testing a Phoenix JSON API](https://robots.thoughtbot.com/testing-a-phoenix-elixir-json-api) 16 | 17 | #### Security 18 | 19 | - [Routing Security with Phoenix](https://www.youtube.com/watch?v=4fSsTdn195g) 20 | -------------------------------------------------------------------------------- /type-systems/resources.md: -------------------------------------------------------------------------------- 1 | ## Learning Resources 2 | 3 | ### Videos 4 | 5 | - Overview of type systems: [Google Tech Talks](https://www.youtube.com/watch?v=h0OkptwfX4g), April 18th, 2007 6 | - Howard-Curry Correspondence 7 | - [Propositions as Types](https://www.youtube.com/watch?v=IOiZatlZtGU) - Philip Wadler 8 | - Category Theory 9 | - [Category Theory, The essence of interface-based design](https://www.youtube.com/watch?v=JMP6gI5mLHc) - Erik Meijer 10 | - [Category Theory for JavaScript Programmers (Series)](https://www.youtube.com/watch?v=-FkgOHvNAU8) - Mike Stay 11 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed as: 8 | 9 | 1. Add `issues` to your list of dependencies in `mix.exs`: 10 | 11 | ```elixir 12 | def deps do 13 | [{:issues, "~> 0.1.0"}] 14 | end 15 | ``` 16 | 17 | 2. Ensure `issues` is started before your application: 18 | 19 | ```elixir 20 | def application do 21 | [applications: [:issues]] 22 | end 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/stack.exs: -------------------------------------------------------------------------------- 1 | defmodule Stack do 2 | use GenServer 3 | 4 | # Server Callbacks 5 | def handle_call(:pop, _from, [head | tail]) do 6 | {:reply, head, tail} 7 | end 8 | 9 | def handle_cast({:push, item}, state) do 10 | {:noreply, [item | state]} 11 | end 12 | end 13 | 14 | # Provide module that the server lives in and initial state 15 | {:ok, pid} = GenServer.start_link(Stack, [:hello]) 16 | 17 | GenServer.call(pid, :pop) 18 | #=> :hello 19 | 20 | GenServer.cast(pid, {:push, :world}) 21 | #=> :ok 22 | 23 | GenServer.call(pid, :pop) 24 | #=> :world 25 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-7-lists/notes.md: -------------------------------------------------------------------------------- 1 | # Lists 2 | 3 | ## Heads and Tails 4 | 5 | We can use the pipe character, `|`, to say that what is on the left hand side is the head of the list, and what is on the right hand side is the tail of the list. 6 | 7 | So: 8 | 9 | ```ex 10 | [3] == [3 | []] 11 | [2, 3] == [2 | [3 | []]] 12 | [1, 2, 3] == [1 | [2 | [3 | []]]] 13 | ``` 14 | 15 | As a result, we can use pattern matching to both match position of elements, and also as a way to collect the head and the tail of a list. 16 | 17 | ```ex 18 | [a, b, b] = [1, 2, 3] 19 | [head | tail] = [1, 2, 3] 20 | ``` 21 | -------------------------------------------------------------------------------- /computer-science/history.md: -------------------------------------------------------------------------------- 1 | # History 2 | 3 | ## Computer Scientists 4 | 5 | ### Alonzo Church 6 | 7 | Part of the foundational work for the Lambda Calculus. 8 | 9 | ### John Backus 10 | 11 | - Turing Award Winner 12 | - Creator of Fortran 13 | - [Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs](http://worrydream.com/refs/Backus-CanProgrammingBeLiberated.pdf) 14 | 15 | ### John Hughes 16 | 17 | - Researcher who's a big proponent of Functional Programming 18 | - Created Quickcheck 19 | - Great video on [Why Functional Programming Matters](https://www.youtube.com/watch?v=Z35Tt87pIpg) 20 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-14-processes/chain.exs: -------------------------------------------------------------------------------- 1 | defmodule Chain do 2 | def counter(next_pid) do 3 | receive do 4 | n -> 5 | send next_pid, n + 1 6 | end 7 | end 8 | 9 | def create_processes(n) do 10 | last = Enum.reduce 1..n, self, 11 | fn (_, send_to) -> 12 | spawn(Chain, :counter, [send_to]) 13 | end 14 | 15 | send last, 0 16 | 17 | receive do 18 | final_answer when is_integer(final_answer) -> 19 | "result is #{inspect(final_answer)}" 20 | end 21 | end 22 | 23 | def run(n) do 24 | IO.puts inspect :timer.tc(Chain, :create_processes, [n]) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-14-processes/spawn-basic.exs: -------------------------------------------------------------------------------- 1 | defmodule Spawn1 do 2 | def greet do 3 | receive do 4 | {sender, msg} -> 5 | send sender, { :ok, "Hello, #{msg}" } 6 | greet 7 | end 8 | end 9 | end 10 | 11 | # Here's a client 12 | pid = spawn(Spawn1, :greet, []) 13 | 14 | # send :: pid, { sender, msg } 15 | send pid, { self, "World" } 16 | 17 | receive do 18 | { :ok, message } -> 19 | IO.puts message 20 | end 21 | 22 | 23 | send pid, { self, "Kermit!" } 24 | receive do 25 | {:ok, message} -> 26 | IO.puts message 27 | after 500 -> 28 | IO.puts "The greeter has gone away :(" 29 | end 30 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/examples/counter.exs: -------------------------------------------------------------------------------- 1 | defmodule Counter.Server do 2 | def start(initial_count \\ 0) do 3 | spawn fn -> listen(initial_count) end 4 | end 5 | 6 | defp listen(count) do 7 | receive do 8 | :inc -> listen(count + 1) 9 | :dec -> listen(count - 1) 10 | {sender, :val } -> 11 | send sender, count 12 | listen(count) 13 | end 14 | end 15 | end 16 | 17 | defmodule Counter.Client do 18 | def inc(pid), do: send(pid, :inc) 19 | def dec(pid), do: send(pid, :dec) 20 | def val(pid) do 21 | send pid, {self, :val} 22 | receive do 23 | val -> val 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-8-dictionaries/maps.exs: -------------------------------------------------------------------------------- 1 | # Maps 2 | map = %{name: "Dave", likes: "Programming", where: "Dallas"} 3 | 4 | map[:name] # "Dave" 5 | map.name # "Dave" 6 | 7 | Map.keys map # [:likes, :name, :where] 8 | Map.values map # ["Programming", "Dave", "Dallas"] 9 | 10 | map1 = Map.drop map, [:where, :likes] # %{name: "Dave"} 11 | map2 = Map.put map, :also_likes, "Ruby" 12 | 13 | Map.has_key? map1, :where # False 14 | 15 | Map.pop map, :name 16 | Map.equal? map, map1 17 | 18 | nestedMap = %{ 19 | foo: %{ 20 | bar: "foobar" 21 | } 22 | } 23 | 24 | # get_in, get_and_update_in 25 | put_in nestedMap.foo.bar, "baz" 26 | update_in nestedMap.foo.bar, &(&1 <> " baz") 27 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-7-lists/complex-lists.exs: -------------------------------------------------------------------------------- 1 | ​def​ test_data ​do​ 2 | [ 3 | [1366225622, 26, 15, 0.125], 4 | [1366225622, 27, 15, 0.45], 5 | [1366225622, 28, 21, 0.25], 6 | [1366229222, 26, 19, 0.081], 7 | [1366229222, 27, 17, 0.468], 8 | [1366229222, 28, 15, 0.60], 9 | [1366232822, 26, 22, 0.095], 10 | [1366232822, 27, 21, 0.05], 11 | [1366232822, 28, 24, 0.03], 12 | [1366236422, 26, 17, 0.025] 13 | ] 14 | ​end​ 15 | 16 | defmodule WeatherHistory do 17 | def for_location_27([]), do: [] 18 | def for_location_27([[time, 27, temp, rain] | tail]) do 19 | [[time, 27, temp, rain] | for_location_27(tail)] 20 | end 21 | def for_location_27([_ | tail]), do: for_location_27(tail) 22 | end 23 | -------------------------------------------------------------------------------- /design/research/research.md: -------------------------------------------------------------------------------- 1 | # Research 2 | 3 | > Research should be a continuous input. 4 | 5 | ## Creating an Experience-centered Company 6 | 7 | [Source](https://blog.intercom.com/autodesks-maria-giudice-on-creating-an-experience-centered-company/) 8 | 9 | > That’s the other thing that’s common is the perspective of put it out there in the wild, get people to use it, learn from it, and change it. That’s great in theory and it works many parts of the time, but the downside of that is you’re potentially putting out really bad product experiences and you are taking a debt – a hit on trust. It takes a lot longer to build back trust than it does to actually invest in making sure that you have tested something before it gets put out there that doesn’t hit the trust threshold. 10 | -------------------------------------------------------------------------------- /backend/elixir/fs/io.exs: -------------------------------------------------------------------------------- 1 | # The IO module is the main mechanism in Elixir for reading and 2 | # writing to :stdio and :stderr 3 | IO.puts "hello world" 4 | IO.gets "yes or no?" 5 | 6 | # File, allows us to open files as IO devices. 7 | {:ok, file} = File.open "hello", [:write] 8 | IO.binwrite file, "world" 9 | File.close file 10 | 11 | File.read "hello" 12 | 13 | # File.rm/1, File.mkdir/1, File.mkdir_p/1 14 | # File.cp_r/2, File.rm_rf/1 15 | 16 | # You can use the ! to throw exceptions, and pattern match 17 | case File.read(file) do 18 | {:ok, body} -> # do something with the `body` 19 | {:error, reason} -> # handle the error caused by `reason` 20 | end 21 | 22 | # Path module 23 | Path.join("foo", "bar") # "foo/bar" 24 | Path.expand("~/hello") # "/Users/joshuablack/hello" 25 | 26 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/lib/kv/bucket.ex: -------------------------------------------------------------------------------- 1 | defmodule KV.Bucket do 2 | @doc """ 3 | Starts a new bucket 4 | """ 5 | def start_link do 6 | Agent.start_link(fn -> %{} end) 7 | end 8 | 9 | @doc """ 10 | Gets a value from the `bucket` by `key` 11 | """ 12 | def get(bucket, key) do 13 | Agent.get(bucket, &Map.get(&1, key)) 14 | end 15 | 16 | @doc """ 17 | Puts the `value` for the given `key` in the `bucket` 18 | """ 19 | def put(bucket, key, value) do 20 | Agent.update(bucket, &Map.put(&1, key, value)) 21 | end 22 | 23 | @doc """ 24 | Deletes `key` from `bucket`. 25 | 26 | Returns the current value of `key`, if `key` exists 27 | """ 28 | def delete(bucket, key) do 29 | Agent.get_and_update(bucket, &Map.pop(&1, key)) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-10-collections/enum.exs: -------------------------------------------------------------------------------- 1 | # The `Enum` module is one of the most used libraries in Elixir 2 | list = Enum.to_list 1..5 3 | 4 | Enum.concat([1, 2, 3], [4, 5, 6]) 5 | 6 | doubled = Enum.map(list, &(&1 * 2)) 7 | 8 | Enum.at(list, 3) # 4 9 | Enum.at(list, 5) # nil 10 | 11 | require Integer 12 | Enum.filter(list, &(&1 > 2)) 13 | 14 | Enum.filter(list, &Integer.is_even/1) 15 | Enum.reject(list, &Integer.is_even/1) 16 | 17 | Enum.sort [3, 4, 5, 1, 2] 18 | Enum.sort(list, &(&1 >= &2)) 19 | 20 | 21 | Enum.take(1..5, 3) 22 | Enum.take_every(1..5, 2) 23 | Enum.take_while(1..5, &(&1 < 4)) 24 | Enum.split(1..5, 3) 25 | 26 | Enum.join(1..5) 27 | Enum.join(1..5, ', ') 28 | 29 | Enum.all? 30 | Enum.any? 31 | Enum.member? 32 | Enum.empty? 33 | 34 | Enump.szip 35 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-7-lists/lists.exs: -------------------------------------------------------------------------------- 1 | defmodule MyList do 2 | def len([]), do: 0 3 | def len([_head | tail]), do: 1 + len(tail) 4 | 5 | def square([]), do: [] 6 | def square([head | tail]), do: [head * head | square(tail)] 7 | 8 | def add_one([]), do: [] 9 | def add_one([head | tail]), do: [head + 1 | add_one(tail)] 10 | 11 | def map([], _func), do: [] 12 | def map([head | tail], func), do: [func.(head) | map(tail, func)] 13 | 14 | def sum(list), do: _sum(list, 0) 15 | defp _sum([], total), do: total 16 | defp _sum([head | tail], total), do: _sum(tail, head + total) 17 | 18 | def reduce([], value, _func) do 19 | value 20 | end 21 | 22 | def reduce([head | tail], value, func) do 23 | reduce(tail, func.(head, value), func) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /backend/elixir/enumerables-and-streams/README.md: -------------------------------------------------------------------------------- 1 | # Enumerables and Streams 2 | 3 | The `Enum` module works on both lists and maps, and really anything that is considered _enumerable_. 4 | 5 | ```ex 6 | # Double all the elements in the list 7 | Enum.map([1, 2, 3], fn x -> x * 2 end) 8 | [2, 4, 6] 9 | 10 | # Find the product of each {key, value} tuple 11 | Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end) 12 | [2, 12] 13 | ``` 14 | 15 | It's important to note that all the functions in the `Enum` module are eager. If we want lazy operations, we'll have to use the `Stream` module. 16 | 17 | Streams are very useful for handling large files or slow resources like network resources because they allow us to wrap resources and guarantee that they are opened right before enumeration and closed afterwards, even in the case of failures. 18 | -------------------------------------------------------------------------------- /backend/elixir/ecto/README.md: -------------------------------------------------------------------------------- 1 | # Ecto 2 | 3 | If you're coming from a traditional ORm background like ActiveRecord, it's common to centralize tasks like database access, query geeneration, and validation in your models. 4 | 5 | In Ecto, these are all divided into separate modules: 6 | 7 | - `Repo`: provides an interface to execute queries against a database. 8 | - `Model`: provides a struct for you to create instances of a specific type with 9 | - `Changeset`: provide you with model validations 10 | 11 | ## Models 12 | 13 | Models are where we end up creating the structs to represent the data inside of our application. Each model defines the fields or our schema as well as their types, it also identifies and defines the relationships with other models. 14 | 15 | Models also handle data validation and type casting with changesets. 16 | -------------------------------------------------------------------------------- /backend/elixir/elixir-in-action/database_server.exs: -------------------------------------------------------------------------------- 1 | defmodule ExampleServer do 2 | # Called the `interface` function that is used by clients to start 3 | # the server process 4 | def start do 5 | spawn(&loop/0) 6 | end 7 | 8 | def run_async(server_pid, query_def) do 9 | send(server_pid, {:run_query, self, query_def}) 10 | end 11 | 12 | def get_result do 13 | receive do 14 | {:query_result, result} -> result 15 | after 5000 -> 16 | {:error, :timeout} 17 | end 18 | end 19 | 20 | defp loop do 21 | receive do 22 | {:run_query, caller, query_def} -> 23 | send(caller, {:query_result, run_query(query_def)}) 24 | end 25 | 26 | loop 27 | end 28 | 29 | defp run_query(query_def) do 30 | :timer.sleep(2000) 31 | 32 | "#{query_def} result" 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /backend/elixir/elixir-in-action/calculator.exs: -------------------------------------------------------------------------------- 1 | defmodule Calculator do 2 | def start do 3 | spawn(fn -> 4 | initial_state = 0 5 | 6 | loop(initial_state) 7 | end) 8 | end 9 | 10 | def add(pid, value) do 11 | send(pid, {:add, value}) 12 | end 13 | 14 | def value(pid, caller) do 15 | send(pid, {:value, caller}) 16 | end 17 | 18 | defp loop(state) do 19 | next_state = receive do 20 | {:value, caller} -> 21 | send(caller, {:response, state}) 22 | state 23 | 24 | {:add, value} -> state + value 25 | {:sub, value} -> state - value 26 | {:mul, value} -> state * value 27 | {:div, value} -> state / value 28 | 29 | message -> 30 | IO.puts "Invalid request #{inspect(message)}" 31 | state 32 | end 33 | 34 | loop(next_state) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Kv.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [app: :kv, 6 | version: "0.1.0", 7 | elixir: "~> 1.3", 8 | build_embedded: Mix.env == :prod, 9 | start_permanent: Mix.env == :prod, 10 | deps: deps()] 11 | end 12 | 13 | # Configuration for the OTP application 14 | # 15 | # Type "mix help compile.app" for more information 16 | def application do 17 | [applications: [:logger], 18 | mod: {KV, []}] 19 | end 20 | 21 | # Dependencies can be Hex packages: 22 | # 23 | # {:mydep, "~> 0.3.0"} 24 | # 25 | # Or git/path repositories: 26 | # 27 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} 28 | # 29 | # Type "mix help deps" for more examples and options 30 | defp deps do 31 | [] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /type-systems/README.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | Understanding computing, algorithms, and how they tie into Category Theory and type systems. 4 | 5 | ## History 6 | 7 | An algorithm is a sequence of instructions followed by a computer. Traditionally this computer was thought of as the person who executed each instruction. However, now we think of this as a device that handles the exeuction for us. 8 | 9 | A formal mathematical definition of computation didn't appear until the 1930s when Church, Gödel, and Turing all published papers about effective computability, including: 10 | 11 | - _Lambda Calculus_: An unsolvable problem of elementary number theory, Alonzo Church, May 1935 12 | - _Recursive Functions_: Stephen Kleene, General recursive functions of natural numbers, Kurt Gödel, July 1935 13 | - _Turing Machines_: On computable numbers, with an application to the Entscheidungsproblem, Alan Turing, May 1936 14 | -------------------------------------------------------------------------------- /backend/elixir/processes/spawn.exs: -------------------------------------------------------------------------------- 1 | # spawn/1 :: fn -> pid 2 | 3 | pid = spawn fn -> 1 + 2 end 4 | Process.alive?(pid) 5 | 6 | # Get the current process 7 | self 8 | self() 9 | 10 | # `send` and `receive` 11 | send self(), {:hello, "world"} 12 | receive do 13 | {:hello, msg} -> msg 14 | {:world, msg} -> "won't match" 15 | end 16 | 17 | # When a message is sent to a process, the message is stored in 18 | # the process mailbox. If no messages in the mailbox match any 19 | # of the patterns, the current process will wait until a matching 20 | # message arrives. 21 | 22 | receive do 23 | {:hello, msg} -> msg 24 | after 25 | 1_000 -> "nothing after 1s" 26 | end 27 | 28 | # send :: pid, any 29 | 30 | # Most common way of spawning in Elixir is `spawn_link` 31 | # There's also Process.link/1 32 | 33 | # In Elixir apps, we often link our processes to supervisors which 34 | # will detect when a process dies and start a new process in its 35 | # place 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/lib/kv/bucket/supervisor.ex: -------------------------------------------------------------------------------- 1 | defmodule KV.Bucket.Supervisor do 2 | use Supervisor 3 | 4 | # A simple module attribute that stores the supervisor name 5 | @name KV.Bucket.Supervisor 6 | 7 | def start_link do 8 | Supervisor.start_link(__MODULE__, :ok, name: @name) 9 | end 10 | 11 | @doc """ 12 | Starts a bucket as a child of our supervisor named `KV.Bucket.Supervisor`. 13 | 14 | We'll use this instead of calling KV.Bucket.start_link directly 15 | """ 16 | def start_bucket do 17 | Supervisor.start_child(@name, []) 18 | end 19 | 20 | @doc """ 21 | Create a new temporary worker for `KV.Bucket`, telling the Supervisor not to 22 | restart the bucket if it dies. The creation of buckets should always pass 23 | through the registry 24 | """ 25 | def init(:ok) do 26 | children = [ 27 | worker(KV.Bucket, [], restart: :temporary) 28 | ] 29 | 30 | supervise(children, strategy: :simple_one_for_one) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GitHub do 2 | require Logger 3 | 4 | @user_agent [{ "User-agent", "Learning Elixir!" }] 5 | 6 | def fetch(user, project) do 7 | Logger.info "Fetching user #{user}'s project #{project}" 8 | 9 | issues_url(user, project) 10 | |> HTTPoison.get(@user_agent) 11 | |> handle_response 12 | end 13 | 14 | def handle_response({ :ok, %{status_code: 200, body: body } }) do 15 | Logger.info "Successful response" 16 | Logger.debug fn -> inspect(body) end 17 | 18 | { :ok, Poison.Parser.parse!(body) } 19 | end 20 | 21 | def handle_response({ _, %{ status_code: status, body: body } }) do 22 | Logger.error "Error #{status} returned" 23 | 24 | { :error, Poison.Parser.parse!(body) } 25 | end 26 | 27 | # Use a Module attribute to fetch the value at compile time 28 | @github_url Application.get_env(:issues, :github_url) 29 | 30 | def issues_url(user, project) do 31 | "#{@github_url}/repos/#{user}/#{project}/issues" 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv_registry.exs: -------------------------------------------------------------------------------- 1 | defmodule KV.Registry do 2 | use GenServer 3 | 4 | ## Client API 5 | @doc """ 6 | Starts the registry 7 | """ 8 | def start_link do 9 | GenServer.start_link(__MODULE__, :ok, []) 10 | end 11 | 12 | @doc """ 13 | Looks up the bucket pid for `name` stored in `server`. 14 | 15 | Returns `{:ok, pid}` if the bucket exists, `:error` otherwise 16 | """ 17 | def lookup(server, name) do 18 | GenServer.call(server, {:lookup, name}) 19 | end 20 | 21 | @doc """ 22 | Ensures there is a bucket associated to the given `name` in `server` 23 | """ 24 | def create(server, name) do 25 | GenServer.cast(server, {:create, name}) 26 | end 27 | 28 | ## Server Callbacks 29 | def init(:ok) do 30 | {:ok, %{}} 31 | end 32 | 33 | def handle_call({:lookup, name}, _from, names) do 34 | {:reply, Map.fetch(names, name), names} 35 | end 36 | 37 | def handle_cast({create, name}, names) do 38 | if Map.has_key?(names, name) do 39 | {:noreply, names} 40 | else 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /front-end/frameworks/angular/RESOURCES.md: -------------------------------------------------------------------------------- 1 | ## Resources 2 | 3 | ### Angular 1.5 4 | 5 | - [Developer Guide - Components](https://docs.angularjs.org/guide/component) 6 | - [Developer Guider - Component Router](https://docs.angularjs.org/guide/component-router) 7 | - [Exploring the Angular 1.5 Component Method](https://toddmotto.com/exploring-the-angular-1-5-component-method/) 8 | - [Pete Bacon Darwin Component Demo](https://github.com/petebacondarwin/ng1-component-demo) 9 | - [Components, Components, Components! ...and AngularJS](https://www.youtube.com/watch?v=AMwjDibFxno) 10 | 11 | ### Other 12 | 13 | - [Refactoring Angular Apps to Component Style](http://teropa.info/blog/2015/10/18/refactoring-angular-apps-to-components.html) 14 | - [Papa John's Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md) 15 | - [AngularJS Developer Guide](https://docs.angularjs.org/guide/concepts#view) 16 | - [Angular - ngNewRouter vs ui-router](https://medium.com/angularjs-meetup-south-london/angular-just-another-introduction-to-ngnewrouter-vs-ui-router-72bfcb228017#.5t8wwz61i) 17 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/shared/getContextForSubtree.md: -------------------------------------------------------------------------------- 1 | # `getContextForSubtree` 2 | 3 | #### `getContextForSubtree = (parentComponent : ?ReactComponent) => Object` 4 | 5 | This seems like a utility for getting the context fiber for a given `parentComponent`. If we're at the Root Node, or just don't have a `parentComponent` then we'll just return an `emptyObject`. 6 | 7 | Otherwise, we'll try and use `ReactInstanceMap` to lookup the instance for the `parentComponent`. If the instance has a `tag` of type `number`, then we'll use `getContextFiber` on the instance. Else, we use `instance._processChildContext(instance._context)`. 8 | 9 | TODO: 10 | 11 | - Document where `_processChildContext` comes from and how `instance._context` gets set 12 | 13 | ## Module 14 | 15 | This module imports the following modules: 16 | 17 | ```js 18 | const ReactInstanceMap = require('ReactInstanceMap'); 19 | const emptyObject = require('emptyObject'); 20 | const invariant = require('invariant'); 21 | ``` 22 | Finally, this module exposes the following exports: 23 | 24 | ```js 25 | getContextForSubtree 26 | ``` 27 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [app: :issues, 6 | escript: escript_config, 7 | version: "0.1.0", 8 | name: "Pragmatic Elixir Project \#1", 9 | elixir: "~> 1.3", 10 | build_embedded: Mix.env == :prod, 11 | start_permanent: Mix.env == :prod, 12 | deps: deps()] 13 | end 14 | 15 | # Configuration for the OTP application 16 | # 17 | # Type "mix help compile.app" for more information 18 | def application do 19 | [applications: [:logger, :httpoison]] 20 | end 21 | 22 | # Dependencies can be Hex packages: 23 | # 24 | # {:mydep, "~> 0.3.0"} 25 | # 26 | # Or git/path repositories: 27 | # 28 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} 29 | # 30 | # Type "mix help deps" for more examples and options 31 | defp deps do 32 | [ 33 | httpoison: "~> 0.8", 34 | poison: "~> 1.5", 35 | ex_doc: "~> 0.11", 36 | earmark: ">= 0.0.0" 37 | ] 38 | end 39 | 40 | defp escript_config do 41 | [ main_module: Issues.CLI ] 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for 9 | # 3rd-party users, it should be done in your "mix.exs" file. 10 | 11 | # You can configure for your application as: 12 | # 13 | # config :kv, key: :value 14 | # 15 | # And access this configuration in your application as: 16 | # 17 | # Application.get_env(:kv, :key) 18 | # 19 | # Or configure a 3rd-party app: 20 | # 21 | # config :logger, level: :info 22 | # 23 | 24 | # It is also possible to import configuration files, relative to this 25 | # directory. For example, you can emulate configuration per environment 26 | # by uncommenting the line below and defining dev.exs, test.exs and such. 27 | # Configuration from the imported file will override the ones defined 28 | # here (which is why it is important to import them last). 29 | # 30 | # import_config "#{Mix.env}.exs" 31 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues.CLI 4 | 5 | import Issues.CLI, only: [ 6 | parse_args: 1, 7 | sort_into_ascending_order: 1, 8 | convert_to_list_of_maps: 1, 9 | ] 10 | 11 | test ":help returned by option parsing with -h and --help options" do 12 | assert parse_args(["-h", "anything"]) == :help 13 | assert parse_args(["--help", "anything"]) == :help 14 | end 15 | 16 | test "three values returned if three given" do 17 | assert parse_args(["user", "project", "99"]) == 18 | { "user", "project", 99 } 19 | end 20 | 21 | test "count is defaulted if two values given" do 22 | assert parse_args(["user", "project"]) == { "user", "project", 4} 23 | end 24 | 25 | test "sort ascending orders the correct way" do 26 | result = ["c", "a", "b"] 27 | |> fake_created_at_list 28 | |> sort_into_ascending_order 29 | issues = for issue <- result, do: issue["created_at"] 30 | 31 | assert issues == ~w{a b c} 32 | end 33 | 34 | defp fake_created_at_list(values) do 35 | data = for value <- values, 36 | do: [{ "created_at", value}, {"other_data", "yyy" }] 37 | convert_to_list_of_maps data 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/stack_improved.exs: -------------------------------------------------------------------------------- 1 | defmodule Stack do 2 | use GenServer 3 | 4 | # Client 5 | def start_link(default) do 6 | GenServer.start_link(__MODULE__, default) 7 | end 8 | 9 | def push(pid, item) do 10 | GenServer.cast(pid, {:push, item}) 11 | end 12 | 13 | def pop(pid) do 14 | GenServer.call(pid, :pop) 15 | end 16 | 17 | # Callbacks 18 | def handle_call(:pop, _from, [head | tail]) do 19 | {:reply, head, tail} 20 | end 21 | 22 | def handle_call(request, from, state) do 23 | super(request, from, state) 24 | end 25 | 26 | def handle_cast({:push, item}, state) do 27 | {:noreply, [item | state]} 28 | end 29 | 30 | def handle_cast(request, state) do 31 | super(request, state) 32 | end 33 | end 34 | 35 | ExUnit.start() 36 | 37 | defmodule StackTest do 38 | use ExUnit.Case, async: true 39 | 40 | setup do 41 | {:ok, stack} = Stack.start_link([]) 42 | {:ok, stack: stack} 43 | end 44 | 45 | test "adds an item to the end of the stack", %{stack: stack} do 46 | assert Stack.push(stack, 1) == :ok 47 | end 48 | 49 | test "pops an item from the top of the stack", %{stack: stack} do 50 | assert Stack.push(stack, 1) == :ok 51 | assert Stack.push(stack, 2) == :ok 52 | 53 | assert Stack.pop(stack) == 2 54 | assert Stack.pop(stack) == 1 55 | end 56 | end 57 | 58 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/test/registry_test.exs: -------------------------------------------------------------------------------- 1 | defmodule KV.RegistryTest do 2 | use ExUnit.Case, async: true 3 | 4 | setup context do 5 | {:ok, registry} = KV.Registry.start_link(context.test) 6 | {:ok, registry: registry} 7 | end 8 | 9 | test "spawns buckets", %{registry: registry} do 10 | assert KV.Registry.lookup(registry, "shopping") == :error 11 | 12 | KV.Registry.create(registry, "shopping") 13 | assert {:ok, bucket} = KV.Registry.lookup(registry, "shopping") 14 | 15 | KV.Bucket.put(bucket, "milk", 1) 16 | assert KV.Bucket.get(bucket, "milk") == 1 17 | end 18 | 19 | test "removes buckets on exit", %{registry: registry} do 20 | KV.Registry.create(registry, "shopping") 21 | 22 | {:ok, bucket} = KV.Registry.lookup(registry, "shopping") 23 | 24 | Agent.stop(bucket) 25 | 26 | assert KV.Registry.lookup(registry, "shopping") == :error 27 | end 28 | 29 | test "removes bucket on crash", %{registry: registry} do 30 | KV.Registry.create(registry, "shopping") 31 | {:ok, bucket} = KV.Registry.lookup(registry, "shopping") 32 | 33 | # Stop the bucket with non-normal reason 34 | Process.exit(bucket, :shutdown) 35 | 36 | # Wait until the bucket is dead 37 | ref = Process.monitor(bucket) 38 | assert_receive {:DOWN, ^ref, _, _, _} 39 | 40 | assert KV.Registry.lookup(registry, "shopping") == :error 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/chapter-14-processes/fibonacci.exs: -------------------------------------------------------------------------------- 1 | defmodule FibSolver do 2 | def fib(scheduler) do 3 | send scheduler, { :ready, self } 4 | 5 | receive do 6 | { :fib, n, client } -> 7 | send client, { :answer, n, fib_calc(n), self } 8 | fib(scheduler) 9 | { :shutdown } -> 10 | exit(:normal) 11 | end 12 | end 13 | 14 | defp fib_calc(0), do: 0 15 | defp fib_calc(1), do: 1 16 | defp fib_calc(n), do: fib_calc(n - 1) + fib_calc(n - 2) 17 | end 18 | 19 | defmodule Scheduler do 20 | def run(num_processes, module, func, to_calculate) do 21 | 1..num_processes 22 | |> Enum.map(fn (_) -> spawn(module, func, [self]) end) 23 | |> schedule_processes(to_calculate, []) 24 | end 25 | 26 | defp schedule_processes(processes, queue, results) do 27 | receive do 28 | {:ready, pid} when length(queue) > 0 -> 29 | [next | tail] = queue 30 | 31 | send pid, {:fib, next, self} 32 | schedule_processes(processes, tail, results) 33 | 34 | {:ready, pid} -> 35 | send pid, {:shutdown} 36 | if length(processes) > 1 do 37 | schedule_processes(List.delete(processes, pid), queue, results) 38 | else 39 | Enum.sort(results, fn {n1, _}, {n2, _} -> n1 <= n2 end) 40 | end 41 | 42 | {:answer, number, result, _pid} -> 43 | schedule_processes(processes, queue, [{number, result} | results ]) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /product-management/podcasts.md: -------------------------------------------------------------------------------- 1 | # Intercom 2 | 3 | Intercom has a great podcast that they host every couple of weeks, where they talk about topics related to product, design, start-ups, and more. 4 | 5 | Some of their Product-related segments are invaluable, as they show how VPs of Product think about Product and Product Management, while also sharing their own tips and strategies for building Products today. 6 | 7 | Below are some of the podcasts that stick out that I've frequently come back to, they may or may not have notes attached to them. 8 | 9 | ## Paul Adams on product 10 | 11 | [Source](https://blog.intercom.com/podcast-paul-adams-on-product/) 12 | 13 | - When you’re building a product, you have to balance the day to day to day activities with the long term vision, thinking in terms of six years, six months, and six weeks. 14 | - Getting the balance right between competing priorities in your product is only achieved by having a well defined roadmap, with clearly defined inputs. 15 | - Most companies focus on 10% incremental improvements. Aiming for a 10x improvement, ten times better than what exists today, can help redefine the problem entirely. 16 | 17 | ## Ilya Fushman on Growing Successful Products 18 | 19 | [Source](https://blog.intercom.com/index-ventures-ilya-fushman-on-growing-successful-products/) 20 | 21 | > If you take a step back and think about what a platform really is, a platform is a marketplace. It’s a multi-sided marketplace that connects the buyers or users of products with the creators or sellers of those products. 22 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/fiber/ReactFiberRoot.md: -------------------------------------------------------------------------------- 1 | # `ReactFiberRoot` 2 | 3 | This module exports the following function: 4 | 5 | ```js 6 | createFiberRoot(containerInfo: any): FiberRoot 7 | ``` 8 | 9 | This function creates an `uninitializedFiber` by calling out to `createHostRootFiber` from `ReactFiber`. It then constructs a `root` POJO to represent a `FiberRoot`, and creates a circular reference by setting `stateNode` on `uninitializedFiber` to be `root`. `root` is then returned. 10 | 11 | ## Module 12 | 13 | This module imports the following modules: 14 | 15 | ```js 16 | const { 17 | createHostRootFiber 18 | } = require('ReactFiber'); 19 | ``` 20 | 21 | This module imports the following types: 22 | 23 | ```js 24 | import type { Fiber } from 'ReactFiber'; 25 | ``` 26 | 27 | Finally, it exports the following `named` exports: 28 | 29 | ```js 30 | createFiberRoot(containerInfo: any): FiberRoot 31 | ``` 32 | 33 | And exports the following types: 34 | 35 | ```js 36 | export type FiberRoot = { 37 | // Any additional information from the host associated with this root. 38 | containerInfo: any, 39 | 40 | // The currently active root fiber. This is the mutable root of the tree. 41 | current: Fiber, 42 | 43 | // Determines if this root has already been added to the schedule for work. 44 | isScheduled: boolean, 45 | 46 | // The work schedule is a linked list. 47 | nextScheduledRoot: ?FiberRoot, 48 | 49 | // Top context object, used by renderSubtreeIntoContainer 50 | context: ?Object, 51 | 52 | pendingContext: ?Object, 53 | }; 54 | ``` 55 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/lib/issues/table_formatter.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.TableFormatter do 2 | 3 | import Enum, only: [ each: 2, map: 2, map_join: 3, max: 1 ] 4 | 5 | def print_table_for_columns(rows, headers) do 6 | with data_by_columns = split_into_columns(rows, headers), 7 | column_widths = widths_of(data_by_columns), 8 | format = format_for(column_widths) 9 | do 10 | puts_one_line_in_columns(headers, format) 11 | IO.puts(separator(column_widths)) 12 | puts_in_columns(data_by_columns, format) 13 | end 14 | end 15 | 16 | def split_into_columns(rows, headers) do 17 | for header <- headers do 18 | for row <- rows, do: printable(row[header]) 19 | end 20 | end 21 | 22 | def printable(str) when is_binary(str), do: str 23 | def printable(str), do: to_string(str) 24 | 25 | def widths_of(columns) do 26 | for column <- columns, do: column |> map(&String.length/1) |> max 27 | end 28 | 29 | def format_for(column_widths) do 30 | map_join(column_widths, " | ", fn width -> "~-#{width}s" end) <> "~n" 31 | end 32 | 33 | def separator(column_widths) do 34 | map_join(column_widths, "-+-", fn width -> List.duplicate("-", width) end) 35 | end 36 | 37 | def puts_in_columns(data_by_columns, format) do 38 | data_by_columns 39 | |> List.zip 40 | |> map(&Tuple.to_list/1) 41 | |> each(&puts_one_line_in_columns(&1, format)) 42 | end 43 | 44 | def puts_one_line_in_columns(fields, format) do 45 | :io.format(format, fields) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/mix.lock: -------------------------------------------------------------------------------- 1 | %{"certifi": {:hex, :certifi, "0.4.0", "a7966efb868b179023618d29a407548f70c52466bf1849b9e8ebd0e34b7ea11f", [:rebar3], []}, 2 | "earmark": {:hex, :earmark, "0.2.1", "ba6d26ceb16106d069b289df66751734802777a3cbb6787026dd800ffeb850f3", [:mix], []}, 3 | "ex_doc": {:hex, :ex_doc, "0.12.0", "b774aabfede4af31c0301aece12371cbd25995a21bb3d71d66f5c2fe074c603f", [:mix], [{:earmark, "~> 0.2", [hex: :earmark, optional: false]}]}, 4 | "hackney": {:hex, :hackney, "1.6.0", "8d1e9440c9edf23bf5e5e2fe0c71de03eb265103b72901337394c840eec679ac", [:rebar3], [{:ssl_verify_fun, "1.1.0", [hex: :ssl_verify_fun, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:certifi, "0.4.0", [hex: :certifi, optional: false]}]}, 5 | "httpoison": {:hex, :httpoison, "0.8.3", "b675a3fdc839a0b8d7a285c6b3747d6d596ae70b6ccb762233a990d7289ccae4", [:mix], [{:hackney, "~> 1.6.0", [hex: :hackney, optional: false]}]}, 6 | "idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []}, 7 | "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, 8 | "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []}, 9 | "poison": {:hex, :poison, "1.5.2", "560bdfb7449e3ddd23a096929fb9fc2122f709bcc758b2d5d5a5c7d0ea848910", [:mix], []}, 10 | "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.0", "edee20847c42e379bf91261db474ffbe373f8acb56e9079acb6038d4e0bf414f", [:rebar, :make], []}} 11 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/notes/control-flow.md: -------------------------------------------------------------------------------- 1 | ## Control Flow 2 | 3 | Only `false` and `nil` are falsey. All other values are truthy 4 | 5 | ```ex 6 | saved = true 7 | 8 | if saved do 9 | # ... 10 | else do 11 | # ... 12 | end 13 | 14 | 15 | unless saved do 16 | #... 17 | end 18 | ``` 19 | 20 | ### `cond` 21 | 22 | Takes a series of expressions and evalutes the first truthy match 23 | 24 | ### `case` 25 | 26 | Control flow based on pattern matching. Given an expression, case will match against each clause until the first pattern is matched. 27 | 28 | ```ex 29 | calculate = fn expression -> 30 | case expression do 31 | {:+, num1, num2} -> num1 + num2 32 | {:-, num1, num2} -> num1 - num2 33 | {:*, num1, 0} -> 0 34 | {:*, num1, num2} -> num1 * num2 35 | {:/, num1, num2} -> num1 / num2 36 | end 37 | end 38 | ``` 39 | 40 | An underscore provides a fall-through: 41 | 42 | ```ex 43 | calculate = fn expression -> 44 | case expression do 45 | {:+, num1, num2} -> num1 + num2 46 | {:-, num1, num2} -> num1 - num2 47 | {:*, num1, 0} -> 0 48 | {:*, num1, num2} -> num1 * num2 49 | _ -> raise "Unable to parse #{inspect expression}" 50 | end 51 | end 52 | ``` 53 | 54 | Can also use it to match any part of a pattern: 55 | 56 | ```ex 57 | calculate = fn expression -> 58 | case expression do 59 | {:+, 7, _} -> "Sevens aren't allowed" 60 | {:+, a, b} -> a + b 61 | end 62 | end 63 | ``` 64 | 65 | ### Guard Clauses 66 | 67 | ``` 68 | calculate = fn expression -> 69 | case expression do 70 | {:+, num1, num2} -> num1 + num2 71 | {:/, num1, num2} when num2 != 0 -> num1 / num2 72 | end 73 | end 74 | ``` 75 | -------------------------------------------------------------------------------- /backend/elixir/gen_server/kv/lib/kv/registry.ex: -------------------------------------------------------------------------------- 1 | defmodule KV.Registry do 2 | use GenServer 3 | 4 | ## Client API 5 | 6 | @doc """ 7 | Starts the registry. 8 | """ 9 | def start_link(name) do 10 | GenServer.start_link(__MODULE__, :ok, name: name) 11 | end 12 | 13 | @doc """ 14 | Looks up the bucket pid for `name` stored in `server`. 15 | 16 | Returns `{:ok, pid}` if the bucket exists, `:error` otherwise. 17 | """ 18 | def lookup(server, name) do 19 | GenServer.call(server, {:lookup, name}) 20 | end 21 | 22 | @doc """ 23 | Ensures there is a bucket associated to the given `name` in `server`. 24 | """ 25 | def create(server, name) do 26 | GenServer.cast(server, {:create, name}) 27 | end 28 | 29 | ## Server Callbacks 30 | 31 | def init(:ok) do 32 | names = %{} 33 | refs = %{} 34 | 35 | {:ok, {names, refs}} 36 | end 37 | 38 | def handle_call({:lookup, name}, _from, {names, _} = state) do 39 | {:reply, Map.fetch(names, name), state} 40 | end 41 | 42 | def handle_cast({:create, name}, {names, refs}) do 43 | if Map.has_key?(names, name) do 44 | {:noreply, names} 45 | else 46 | {:ok, pid} = KV.Bucket.Supervisor.start_bucket 47 | 48 | ref = Process.monitor(pid) 49 | refs = Map.put(refs, ref, name) 50 | names = Map.put(names, name, pid) 51 | 52 | {:noreply, {names, refs}} 53 | end 54 | end 55 | 56 | def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do 57 | {name, refs} = Map.pop(refs, ref) 58 | names = Map.delete(names, name) 59 | 60 | {:noreply, {names, refs}} 61 | end 62 | 63 | def handle_info(_msg, state) do 64 | {:noreply, state} 65 | end 66 | 67 | @doc """ 68 | Stops the registry. 69 | """ 70 | def stop(server) do 71 | GenServer.stop(server) 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /product-management/videos.md: -------------------------------------------------------------------------------- 1 | # Videos 2 | 3 | ## [Keeping Your Product Relevant](https://www.youtube.com/watch?v=8PT40bNEKtM) 4 | 5 | Des Traynor, Intercom 6 | 7 | > Obsess about your problem, not your product. 8 | 9 | ## [10x not 10%: Product management by orders of magnitude](https://vimeo.com/141675862) 10 | 11 | Ken Norton, Mind the Product (2015) 12 | 13 | ## [Product Roadmaps](https://www.youtube.com/watch?v=VRduWvP2VLM) 14 | 15 | Des Traynor, Intercom 16 | 17 | ## [Product Strategy in a Growing Company](https://www.youtube.com/watch?v=ygUQNsn6iwU) 18 | 19 | Des Traynor, Intercom 20 | 21 | ### Quotes 22 | 23 | > Focus on the things that don't change 24 | 25 | > Does it improve, complement, or innovate existing features? 26 | 27 | > A product team measuring its success through “features shipped” is like a parent measuring their success by “presents purchased” 28 | 29 | ### Highlights 30 | 31 | - ["Diluting the core value"](https://youtu.be/ygUQNsn6iwU?t=580) 32 | 33 | ## [Thinking through the funnel](https://www.youtube.com/watch?v=mgj-fxZHoys) 34 | 35 | Des Traynor, Intercom 36 | 37 | ### Highlights 38 | 39 | - [Talking to people in the funnel](https://youtu.be/mgj-fxZHoys?t=633) 40 | - [What is customer onboarding?](https://youtu.be/mgj-fxZHoys?t=791) 41 | - [Great example of why you should know what you’re building, and how you need to make sure you know how people are using it](https://youtu.be/2u_r3o4HCw8?t=278) 42 | 43 | ## [Find Product & Market Fit through Customer Conversations](https://www.youtube.com/watch?v=2u_r3o4HCw8) 44 | 45 | Des Traynor, Intercom 46 | 47 | > You find and maintain product market fit by having customer conversations with the right people, at the right time, in the right place, asking the right questions and then acting on the feedback. 48 | 49 | ### Highlights 50 | 51 | - [You have to start with a product that solves a problem that you understand](https://youtu.be/mgj-fxZHoys?t=2112) 52 | -------------------------------------------------------------------------------- /backend/elixir/workshops/elixir_express/notes/basics.md: -------------------------------------------------------------------------------- 1 | ## Basics 2 | 3 | ### Types 4 | 5 | - Integer 6 | - Float 7 | - Atom 8 | - Tuple `{:ok, :foo, :bar}` 9 | - List 10 | - Bitstring 11 | - Pid 12 | 13 | #### Tuple 14 | 15 | ```ex 16 | # Allocated continuously in memory, set length, set order 17 | is_tuple {1, 2, 3} 18 | ``` 19 | 20 | #### List 21 | 22 | ```ex 23 | # Stored as a linked list, so length is an O(n) operation 24 | is_list [1, 2, 3] 25 | 26 | [head | tail] = [1, 2, 3, 4, 5]; 27 | head # 1 28 | tail # [2, 3, 4, 5] 29 | 30 | [1, 2, third | rest ] = [1, 2, 3, 4, 5, 6] 31 | third # 3 32 | rest # [4, 5, 6] 33 | 34 | list = [1, 2, 3] 35 | hd list 1 36 | tl list # [2, 3] 37 | 38 | Enum.at([2, 4, 6], 0) # 2 39 | Enum.reverse list # [3, 2, 1] 40 | ``` 41 | 42 | ##### Keyword Lists 43 | 44 | ```ex 45 | types = [atom: "Atom", tuple: "Tuple"] 46 | types[:atom] # "Atom" 47 | types[:not_exists] # nil 48 | 49 | [{:atom, "Atom"}] == [atom: "Atom"] # true 50 | 51 | Keyword.keys types # [:atom, :tuple] 52 | Keyword.values types # ["Atom", "Tuple"] 53 | 54 | if true, [do: "it's true"} # it's true 55 | ``` 56 | 57 | ### Variable Binding 58 | 59 | ```ex 60 | sum = 10 61 | sum_val = fn -> IO.puts "Sum value was #{sum}" end 62 | 63 | sum_val.() # 10 64 | 65 | sum = 12 66 | 67 | sum_val.() # 10, doesn't change! Just the binding to sum after the re-bind changes 68 | ``` 69 | 70 | ### Anonymous functions 71 | 72 | ```ex 73 | add = fn a, b -> 74 | a + b 75 | end 76 | 77 | add.(1, 2) # 3 78 | 79 | # Shorthand 80 | Enum.map [3, 6, 9], &(&1 * 2) 81 | 82 | # Same as 83 | Enum.map [3, 6, 9], fn i -> i * 2 end 84 | ``` 85 | 86 | ### Named Functions 87 | 88 | ```ex 89 | defmodule Weather do 90 | def celsius_to_fahrenheit(celsius) do 91 | (celsius * 1.8) + 32 92 | end 93 | 94 | def high, do: 50 95 | def low, do: 32 96 | end 97 | 98 | Weather.high 99 | 100 | Weather.celsius_to_fahrentheight 20 101 | ``` 102 | -------------------------------------------------------------------------------- /database/redis/README.md: -------------------------------------------------------------------------------- 1 | # `redis` 2 | 3 | ## Up & Running 4 | 5 | Using docker: 6 | 7 | ```bash 8 | # Start a redis instance 9 | docker run --name some-redis -d redis 10 | 11 | # Link to it with `redis-cli` 12 | docker run -it --link some-redis:redis --rm redis redis-cli -h redis -p 6379 13 | ``` 14 | 15 | ## Operations (with `redis-cli`) 16 | 17 | ### Using `SET` 18 | 19 | ```bash 20 | # Set a string value for key `mykey` 21 | > set mykey somevalue 22 | OK 23 | > get mykey 24 | "somevalue" 25 | ``` 26 | 27 | Notes: 28 | 29 | - `SET` performs an assignment, so it will replace any existing value already stored for the key. 30 | 31 | ### Increment with `incr` 32 | 33 | ```bash 34 | > set counter 100 35 | OK 36 | > incr counter 37 | (integer) 101 38 | > decr counter 39 | (integer) 100 40 | > incrby counter 5 41 | (integer) 105 42 | > decrby counter 5 43 | (integer) 100 44 | ``` 45 | 46 | ### Working with the key space 47 | 48 | ```bash 49 | > set mykey hello 50 | OK 51 | > exists mykey 52 | (integer) 1 53 | > del mykey 54 | (integer) 1 55 | > exists mykey 56 | (integer) 0 57 | > del mykey 58 | (integer) 0 59 | ``` 60 | 61 | ### Working with lists 62 | 63 | ```bash 64 | # Push to the "right" end of the array 65 | # Return the length of the list 66 | > rpush mylist A 67 | (integer) 1 68 | > rpush mylist B 69 | (integer) 2 70 | # Push to the "left" end of the array, i.e. append 71 | > lpush mylist first 72 | (integer) 3 73 | # Get the elements from the beginning to the end 74 | # of the list 75 | > lrange mylist 0 -1 76 | 1) "first" 77 | 2) "A" 78 | 3) "B" 79 | ``` 80 | 81 | ### Redis hashes 82 | 83 | ```bash 84 | # Commands 85 | hmset key field value [field value ...] 86 | hget key field 87 | hgetall key 88 | ``` 89 | 90 | ```bash 91 | # Examples 92 | > hmset user:1000 username joshblack 93 | OK 94 | ``` 95 | 96 | ### Redis Sets 97 | 98 | > Redis Sets are unordered collections of strings 99 | 100 | ```bash 101 | # Commands 102 | sadd key member [member ...] 103 | smembers key 104 | sismember key member 105 | ``` 106 | -------------------------------------------------------------------------------- /backend/elixir/pragmatic-elixir/projects/issues/lib/issues/cli.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.CLI do 2 | import Issues.TableFormatter, only: [ 3 | print_table_for_columns: 2 4 | ] 5 | 6 | @default_count 4 7 | 8 | @moduledoc """ 9 | Handle the command line parsing and the dispact to various functions that 10 | end up generating a table of the last _n_ issues in a GH project 11 | """ 12 | 13 | def main(argv) do 14 | argv 15 | |> parse_args 16 | |> process 17 | end 18 | 19 | def run(argv) do 20 | argv 21 | |> parse_args 22 | |> process 23 | end 24 | 25 | @doc """ 26 | `argv` can be -h or --help, which returns :help. 27 | 28 | Otherwise, it is a GitHub user name, project name, and (optionally) the 29 | number of entries to format. 30 | 31 | Return a tuple of `{ user, project, count }`, or `:help` if help was 32 | given 33 | """ 34 | def parse_args(argv) do 35 | parse = OptionParser.parse( 36 | argv, 37 | switches: [help: :boolean], 38 | aliases: [h: :help] 39 | ) 40 | 41 | case parse do 42 | { [help: true], _, _ } -> :help 43 | 44 | { _, [ user, project, count], _ } -> 45 | { user, project, String.to_integer count } 46 | 47 | { _, [ user, project], _ } -> {user, project, @default_count } 48 | 49 | _ -> :help 50 | end 51 | end 52 | 53 | def process(:help) do 54 | IO.puts """ 55 | usage: issues [ count | #{@default_count}] 56 | """ 57 | System.halt(0) 58 | end 59 | 60 | def process({ user, project, count }) do 61 | Issues.GitHub.fetch(user, project) 62 | |> decode_response 63 | |> convert_to_list_of_maps 64 | |> sort_into_ascending_order 65 | |> Enum.take(count) 66 | |> print_table_for_columns(["number", "created_at", "title"]) 67 | end 68 | 69 | def decode_response({ :ok, body }), do: body 70 | def decode_response({ error, error }) do 71 | {_, message} = List.keyfind(error, "message", 0) 72 | IO.puts "Error fetching from GitHub #{message}" 73 | 74 | System.halt(2) 75 | end 76 | 77 | def convert_to_list_of_maps(list) do 78 | list 79 | |> Enum.map(&Enum.into(&1, Map.new)) 80 | end 81 | 82 | def sort_into_ascending_order(list_of_issues) do 83 | Enum.sort list_of_issues, 84 | fn i1, i2 -> i1["created_at"] <= i2["created_at"] end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /design/design-and-choice.md: -------------------------------------------------------------------------------- 1 | # Design and Choice 2 | 3 | > Alice Rawsthorn 4 | 5 | [Source](https://design.blog/2016/08/17/alice-rawsthorn-on-design-and-choice/) 6 | 7 | ## Notes 8 | 9 | Alice Rawsthorn presents a great piece on how we enable choices for people in a digital world. The preamble provides a very clear context for why this is important in the physical world, with an incredible example of a young woman endlessly fighting for the choice of individuality in an industrialized pipeline. 10 | 11 | It quickly becomes clear that Rawsthorn is walking a very fine line between the endless sea of possibilities, and a path most chosen. It's seemingly an endless struggle that never quite reaches equilibrium as each side fights to be heard. I think it's brilliant to see that, as humans, we have groups of individuals who very quickly want to standardize a process in order to create something cheap and usable for the masses. Yet, with this mass-production comes trade-offs. And it becomes increasingly important that we pick the right trade-offs. 12 | 13 | Picking the right trade-offs is immediately present when we look at the physical world. We live in buildings that need to follow some degree of codes and regulations, yet each one offers some kind of variance from its immediate neighbors. In this example, the lack of choice imposed on us has a positive impact, and provides a guarantee of safety. 14 | 15 | In a digital world, it seems that choice can manifest itself in many mays. I think the most common representations of this fall into the categories of WYSIWYG editors, drag-and-drop UI interfaces, and other customization tools that affect the user on the surface. When Rawsthorn highlighted the process of Facebook's eventual change of a "gender options" UI element into a free-form field, I think it becomes very clear that the choices that are important to us are the ones that allow us to define ourselves. This can be in a direct way, such as in the "gender options" presented in the previous example, or it can be in an indirect way the same way we can customize our clothes or our homes. 16 | 17 | I think Rawsthorn hits on this point very well, saying: 18 | 19 | > Choice will be a defining element of design in future. As our personal identities become subtler and more singular, we will wish to make increasingly nuanced choices about the design of many aspects of our lives. 20 | 21 | While this makes obvious sense in a consumer context, I'm really curious what this means in an enterprise/professional setting. 22 | -------------------------------------------------------------------------------- /design/designing-for-wide-walls.md: -------------------------------------------------------------------------------- 1 | # Designing for Wide Walls 2 | 3 | > Mitchel Resnick 4 | 5 | [Source](https://design.blog/2016/08/25/mitchel-resnick-designing-for-wide-walls/) 6 | 7 | ## Notes 8 | 9 | There's an interesting point that Resnick brings up that came from his mentor, Seymour Papert, where Seymour says: 10 | 11 | > For a technology to be effective, he said, it should provide easy ways for novices to get started (low floor) but also ways for them to work on increasingly sophisticated projects over time (high ceiling). 12 | 13 | And this idea seems incredibly powerful as it seems to cover such a wide range of topics, and explains our initial reactions to most things. While Resnick applies this in the context of technology, it can very easily be applied to whether or not we'll play a new video game, try out a new recipe, etc. This can be taken further into anything that we would engage with consistently, as the level of our engagement corresponds to how easily we can get up-and-running, and subsequently how far we can take our craft. 14 | 15 | The important distinction that Resnick makes in this post is that it's no longer good enough to just have this dichotomy of a low floor and a high ceiling, we also need to have wide walls. The wide wall analogy tries to pinpoint the fact that we need to connect with what we're working on in a way that's personally meaningful to us. As Resnick admits, it's impossible to create a single project that will be meanginful to all kids. As a result, high engagement only comes from appealing to all. And this universal appeal comes from support for a wide diversity of pathways. 16 | 17 | This support for a wide diversity of pathways seems incredibly important right now. As Resnick notes in his final paragraph: 18 | 19 | > Our ultimate goal is to help all kids develop their thinking, develop their voices, and develop their identities. None of that will happen unless we continually ask: Who are we including? Who are we excluding? And how can we provide everyone—everyone—with opportunities for exploring, experimenting, and expressing themselves. 20 | 21 | This ultimately should be our goal in Technology. There's no excuse for us to not leverage technology to make sure that we include all in the things we create. In the past, the mere scale of having to support so many use-cases may have been incredibly daunting. And, as a result, some things might have slipped. But now, we have these machines capable of doing fantastic things. Machines that are finally capable of tackling the scaling issues that have plagued us for so long. It'd be a shame if we couldn't use them to help in this area. 22 | -------------------------------------------------------------------------------- /design/the-lessons-of-good-design.md: -------------------------------------------------------------------------------- 1 | # The Lessons of Good Design 2 | 3 | > Julie Zhou 4 | 5 | [Source](https://design.blog/2016/09/01/julie-zhuo-on-the-lessons-of-good-design/) 6 | 7 | ## Notes 8 | 9 | > You know you have a good design when you show it to people and they say, “oh, yeah, of course,” like the solution was obvious. 10 | 11 | > Still looking at me, he continued: “It’s not ever obvious to come up with, though. You could be doing months and months of iteration before you come up with that obvious solution.” 12 | 13 | Good design feels obvious - this is what it means to me today: 14 | 15 | 1. “Good” design means it is a) valuable: you’re solving a real problem† for people; b) easy to use: people find it understandable, accessible and fast; and c) well-crafted: the entire experience feels designed with thought and care.‡ 16 | 2. If you cannot get a group of people for whom your product is designed to generally agree that your design is good, it’s not good. 17 | 3. If you cannot get a group of designers to generally agree that your design is easy to use and well crafted, then it isn’t. 18 | 4. The greatest frustration is feeling like you’re getting too much criticism from too many people (which, according to #2, means your design is not yet good). This is either because a) you’re working under too many constraints; b) you’re not exploring solutions broadly enough; or c) the problem is beyond your current skill level. 19 | 5. If you’re working under too many constraints that make it impossible to get to a solution that is obviously good, you need to voice that loud and clear with your team. 20 | 6. If you’re feeling the frustration of #3 but aren’t sure why or how to make progress, the most powerful and effective thing you can do is take a swig of humility juice, admit that you’re stuck, and ask for help. 21 | 7. Obviousness comes from conforming to people’s existing mental models. Don’t waste time reinventing common UI patterns or paradigms unless they are at least 2x better, or you have some critical brand reason to do so. 22 | 8. Better design does not mean more design. Often, the most obvious designs are invisible. 23 | 24 | †Ask: What problem is your product or service trying to solve? If you cannot describe it to someone else and have them instantly understand the pain/frustration/annoyance of this problem, then what you’re building is probably never going to get much traction. 25 | 26 | ‡Remember: Quality is a bar, not a tradeoff. I’m not saying that quality has to be your top value, or that it’s necessary for success. But if you do talk about quality, or you do happen to hold it in regard, understand that at the highest levels, quality happens because it cannot happen otherwise. 27 | -------------------------------------------------------------------------------- /backend/elixir/gen_server.md: -------------------------------------------------------------------------------- 1 | # GenServer 2 | 3 | A GenServer is implemented in two parts: the client API and the server callbacks. The client and server run in separate processes, with the client passing messages back and forth the the server as its functions are called. 4 | 5 | ```ex 6 | defmodule KV.Registry do 7 | use GenServer 8 | 9 | ## Client API 10 | def start_link 11 | GenServer.start_link(__MODULE__, :ok, []) 12 | end 13 | 14 | def lookup(server, name) do 15 | GenServer.call(server, {:lookup, name}) 16 | end 17 | 18 | def create(server, name) do 19 | GenServer.cast(server, {:create, name}) 20 | end 21 | 22 | ## Server Callbacks 23 | def init(:ok) do 24 | {:ok, %{}} 25 | end 26 | 27 | def handle_call({:lookup, name}, _from, names) do 28 | {:reply, Map.fetch(names, name), names} 29 | end 30 | 31 | def handle_cast({:create, name}, names) do 32 | if Map.has_key?(names, name) do 33 | {:noreply, names} 34 | else 35 | {:ok, bucket} = KV.Bucket.start_link 36 | {:noreply, Map.put(names, name, bucket)} 37 | end 38 | end 39 | end 40 | ``` 41 | 42 | The first function for `GenServer` that we use is `start_link/3` which starts a new GenServer passing in three arguments: 43 | 44 | - The module where the server callbacks are implemented, in this case `__MODULE__`, meaning the current module 45 | - The initialization arguments, in this case the atom `:ok` 46 | - A list of options which can, for example, hold the name of the server. 47 | 48 | There are two types of requests you can send to a GenServer: 49 | 50 | - `call`: synchronous, and the server must send a response back to such requests 51 | - `cast`: asynchronous and th e server won't send a response back 52 | 53 | For the server callbacks, `init/1` is a callback that receives the argument given to `GenServer.start_link/2`. 54 | 55 | For `call/2` requests, we implement a `handle_call/3` callback the receives the `request`, the process from which we received the request `_from`, and the current server state `names`. The `handle_call/3` callback returns a tuple in the format `{:reply, reply, new_state}`, where `reply` is what will be sent to the client and the `new_state` is the new server state. 56 | 57 | ### `call`, `cast`, or `info`? 58 | 59 | Deciding when to use `handle_call/3`, `handle_cast/2`, and `handle_info/2` is straightforward: 60 | 61 | - `handle_call/3` must be used for synchronous requests, and is the default choice to apply backpressure while you're waiting for a server reply 62 | - `handle_cast/2` is used for async requests, when you don't care about a reply. It _does not_ guarantee that the server receives the message and should be used sparingly. 63 | - `handle_info/2` is used for all other messages a server may receive that are not sent via `cast` or `call`, including regular messages sent with `send/2`. 64 | -------------------------------------------------------------------------------- /life/Ten Lessons I wish I had been Taught.md: -------------------------------------------------------------------------------- 1 | ## Ten Lessons I wish I had been Taught 2 | 3 | > Gian-Carlo Rota MIT, April 20, 1996 4 | 5 | [Source](http://alumni.media.mit.edu/~cahn/life/gian-carlo-rota-10-lessons.html#expository) 6 | 7 | ### Highlights 8 | 9 | 1. Lecturing 10 | - Evey lecture should make only one point, and should re-iterate on that point multiple times for full-effect. 11 | - Don't ever run overtime! 12 | - Relate to your audience, "Everyone in the audience has come to listen to your lecture with the secret hope of hearing their work mentioned." 13 | - Give the audeince something to take home. 14 | 2. Blackboard (Whiteboard now?) Technique 15 | - Make sure the board is spotless 16 | - Start writing on the top-left hand corner. Just think of the people copying what you're saying down in their notebooks! 17 | 3. Publish the same result serveral times 18 | - Iteration is the most valuable process. 19 | - Start getting feedback early and often and with whoever you can 20 | 4. You are more likely to be remembered by your expository work 21 | - Talks about famous mathematicians and how they became known not for their original work, or what they were good at, but by popular publishing efforts that were just updated regurgitations of previous thoughts. 22 | 5. Ever mathematician has only a few tricks 23 | - Pretty much what the title says. Even the best of us rely on repeating tricks that we know to get results. These are definitely what we're comfortable in, but perhaps it's because we know they can reliably product results 24 | 6. Do not worry about your mistakes 25 | - There are two kinds of mistakes: fatal ones that destroy a theory, and contingent ones which are useful in testing the stability of a theory 26 | - This paragraph is pretty interesting, want to revisit to see if there are other insights to get out of it that apply to CS 27 | 7. Use the Feynman method 28 | - Richard Feynman was fond of giving the following advice on how to be a genius. You have to keep a dozen of your favorite problems constantly present in your mind, although by and large they will lay in a dormant state. Every time you hear or read a new trick or a new result, test it against each of your twelve problems to see whether it helps. Every once in a while there will be a hit, and people will say: "How did he do it? He must be a genius!" 29 | 8. Give lavish acknowledgements 30 | - Give credit when credit is due, and sometimes just give credit anyways. 31 | 9. Write informative introductions 32 | - Motivate people as to the why, even back then people rarely had the time or patience to go through something. Now, even less so. Provide an enticing outline or some form of motivator to hook the reader to engage them effectively. 33 | 10. Be prepared for old age 34 | - "My late friend Stan Ulam used to remark that his life was sharply divided into two halves. In the first half, he was always the youngest person in the group; in the second half, he was always the oldest. There was no transitional period." 35 | -------------------------------------------------------------------------------- /backend/elixir/basics.md: -------------------------------------------------------------------------------- 1 | ## Elixir Basics 2 | 3 | Taken from [Elixir School](http://elixirschool.com/) 4 | 5 | ### Basics 6 | 7 | Elixir supports the basic operators +, -, *, and / as you would expect. It’s important to notice that / will always return a float. 8 | 9 | If you need integer division or the division remainder, Elixir comes with two helpful functions to achieve this: 10 | 11 | ```ex 12 | iex> div(10, 5) 13 | 2 14 | iex> rem(10, 3) 15 | 1 16 | ``` 17 | 18 | An interesting feature is that any two types in Elixir can be compared, the order being: 19 | 20 | ``` 21 | number < atom < reference < functions < port < pid < tuple < maps < list < bitstring 22 | ``` 23 | 24 | #### String Interpolation 25 | 26 | ```ex 27 | name = "Sean" 28 | "Hello ${name}" 29 | ``` 30 | 31 | #### String Concatenation 32 | 33 | ```ex 34 | name = "Sean" 35 | "Hello " <> name 36 | ``` 37 | 38 | ### Collections 39 | 40 | > List, tuples, keywords, maps, and functional combinators 41 | 42 | #### Lists 43 | 44 | Lists are implemented as linked lists, so accessing length is an `O(n)` operation. It's typically faster to prepend than append. 45 | 46 | ```ex 47 | list = [3.41, :pie, "Apple"] 48 | ["First"] ++ list 49 | list ++ ["Last"] 50 | ``` 51 | 52 | ##### List Subtraction 53 | 54 | ```ex 55 | list = ["foo", :bar, 42] -- [42, "bar"] 56 | ``` 57 | 58 | ##### Head / Tail 59 | 60 | ```ex 61 | hd [3.41, :pie, "Apple"] # 3.41 62 | tl [3.41, :pie, "Apple"] # [:pie, "Apple"] 63 | ``` 64 | 65 | #### Tuples 66 | 67 | Tuples are stored contiguously in memory, making accessing their length fast but modification is expesnive. 68 | 69 | ``` 70 | tuple = {:foo, :bar, :baz} 71 | ``` 72 | 73 | #### Keyword Lists 74 | 75 | Keywords and maps are the associative collections of Elixir. In Elixir, a keyword list is a special list of tuples whose first element is an atom; they share performance with lists 76 | 77 | ```ex 78 | iex> [foo: "bar", hello: "world"] 79 | [foo: "bar", hello: "world"] 80 | iex> [{:foo, "bar"}, {:hello, "world"}] 81 | [foo: "bar", hello: "world"] 82 | ``` 83 | 84 | - Keys are atoms 85 | - Keys are ordered 86 | - Keys are not unique 87 | 88 | #### Maps 89 | 90 | ``` 91 | iex> map = %{:foo => "bar", "hello" => :world} 92 | %{:foo => "bar", "hello" => :world} 93 | iex> map[:foo] 94 | "bar" 95 | iex> map["hello"] 96 | :world 97 | ``` 98 | 99 | Maps containing only atom keys: 100 | 101 | ```ex 102 | iex> %{foo: "bar", hello: "world"} 103 | %{foo: "bar", hello: "world"} 104 | ``` 105 | 106 | ### Enums 107 | 108 | > A set of algoirthms for enumerating over collections 109 | 110 | ```ex 111 | Enum.all?([], fn() => ... end) 112 | Enum.any?([], fn() => ... end) 113 | Enum.chunk([1, 2, 3, 4, 5, 6], 2) # [[1, 2], [3, 4], [5, 6]] 114 | Enum.each(["one", "two", "three"], fn(s) -> IO.puts(s) end) 115 | Enum.map([0, 1, 2, 3], fn(x) -> x - 1 end) 116 | Enum.reduce([1, 2, 3], 10, fn(x, acc) -> x + acc end) 117 | Enum.min([5, 3, 0, -1]) 118 | Enum.max([5, 3, 0, -1]) 119 | ``` 120 | 121 | ### Pattern Matching 122 | 123 | -------------------------------------------------------------------------------- /type-systems/flow-intro.md: -------------------------------------------------------------------------------- 1 | ## Flow Intro 2 | 3 | ```js 4 | /** 5 | * Primitives: boolean, number, string, null, void 6 | * Also supports: any, mixed 7 | * 8 | * Optional object properties and optional function parameters 9 | * have the type T|void, for some type T. 10 | */ 11 | 12 | // Optional signature is keyName? 13 | type optionalObject = { 14 | foo?: string 15 | }; 16 | 17 | const valid: optionalObject = { 18 | foo: 'foo' 19 | }; 20 | 21 | const undefinedButValid: optionalObject = { 22 | foo: undefined, 23 | }; 24 | 25 | // null is not a string, nor void 26 | // const nullAndInvalid: optionalObject = { 27 | // foo: null, 28 | // }; 29 | 30 | type Maybe = T | void | null; 31 | 32 | // Maybe types are foo: ?string 33 | // const maybeFunction = (foo: Maybe) => { 34 | const maybeFunction = (foo: ?string) => { 35 | (foo: string | void | null); 36 | }; 37 | 38 | maybeFunction('foo'); 39 | maybeFunction(undefined); // void 40 | maybeFunction(); 41 | maybeFunction(null); 42 | 43 | 44 | /** 45 | * Literal Types 46 | * 47 | * So we have booleans for admitting true and false, numbers for 48 | * any number, and string for any string. However, sometimes it 49 | * can be useful to specify types that admit a single value. For 50 | * this, we have something called a Literal Type. 51 | * 52 | * These can be used for enums, disjoint unions, and for overloading. 53 | */ 54 | // ("bar": "foo"); // Expected string literal `foo`, got `bar` instead 55 | 56 | // type Nothing = void; 57 | // type Maybe = T | Nothing; 58 | 59 | // In Type Thoery, the bottom type is the type that has no values. It is also 60 | // called the zero, or empty, type and is sometimes denoted with falsum. 61 | 62 | type Node = { 63 | value: T | 'root'; 64 | left?: Tree; 65 | right?: Tree; 66 | }; 67 | 68 | // type Empty = null | void; 69 | // type Maybe = T | null | void; 70 | // type Tree = Empty | Node; 71 | type Tree = ?Node; 72 | 73 | const t: Tree = { 74 | value: 'root', 75 | left: { 76 | value: 1, 77 | left: { 78 | value: 3, 79 | }, 80 | }, 81 | right: { 82 | value: 2, 83 | }, 84 | }; 85 | 86 | // Defining module interfaces 87 | // Importing external code 88 | 89 | // Unbounded Polymorphism 90 | // Bounded Polymorphism 91 | 92 | // Not all values `obj: T` have a property `x`, let alone a property `x` that 93 | // is a number given the additional requirement imposed by Math.abs(); 94 | // function unbounded(obj: T): T { 95 | // console.log(Math.abs(obj.x)); 96 | // return obj; 97 | // }; 98 | 99 | // Allows us to have signatures and definitions to specify relationships 100 | // between their type parameters, without having to sacrifice the benefits of 101 | // generics 102 | // function bounded(obj: T): T { 103 | // console.log(Math.abs(obj.x)); 104 | // return obj; 105 | // } 106 | 107 | // Disjoint Unions 108 | // string and numbers supported 109 | type BinaryTree = 110 | { kind: 'leaf', value: number } | 111 | { kind: 'branch', left: BinaryTree, right: BinaryTree, value: number }; 112 | ``` 113 | -------------------------------------------------------------------------------- /backend/elixir/concurrency.md: -------------------------------------------------------------------------------- 1 | # Elixir and Concurrency 2 | 3 | Erlang is all about writing highly available systems -- systems that run forever and are always able to meaningfully respond to client requests. To make your system highly available, you have to tackle the following challenges: 4 | 5 | - Minimize, isolate, and recover from the effets of runtime errors (fault tolerance) 6 | - Handle a load increase by adding more hardware resources without changing or redeploying code (scalability) 7 | - Run your system on multiple machines so that others can take over if one machine crashes (distribution) 8 | 9 | Concurrency plays an important role in achieving HA. In BEAM, a unit of concurrency is a process: a basic building block that makes it possible to build scalable, fault-tolerant, distributed systems. Using a dedicated process for each task, you can take advantage of all available CPU cores and parallelize the work as much as possible. 10 | 11 | BEAM processes are completely isolated, sharing no memory and a crash on one process won't take down other processes. BEAM also provides a means to detect a process crash and do something about it. 12 | 13 | Each process can also manage some state, and can receive messages from other processes to manipulate or retrieve state. 14 | 15 | 16 | ## Creating processes 17 | 18 | We can use the auto-loaded `spawn/1` function to create new processes: 19 | 20 | ```ex 21 | spawn(fn -> 22 | # ... 23 | end) 24 | ``` 25 | 26 | After the process is created, `spawn/1` immediately returns and the process's execution continues. The lambda passed into `spawn/1` is ran concurrently, and the memory of its process is released once the lambda is done and the spawned process exits. 27 | 28 | ## Message Passing 29 | 30 | Each process maintains its own "mailbox", which is simply a FIFO queue that allows the process to process messages as they are received from other processes. You send messages using the `pid` associated to a process, and any message sent to a process in deep-copied since processes can't share memory. 31 | 32 | To send messages, we can use `send/2` 33 | 34 | ```ex 35 | send(pid, {:ok, "message"}) 36 | ``` 37 | 38 | Which we can then read inside of the process using a `receive` block: 39 | 40 | ```ex 41 | receive do 42 | {:ok, message} -> #... 43 | {:error, reason} -> #... 44 | end 45 | ``` 46 | 47 | `receive` here tries to find the first message in the process' mailbox that can be matched against any of the provided clauses. 48 | 49 | ## Server Processes 50 | 51 | A Server Process is an informal name for a process that: 52 | 53 | - runs for a long time (or forever) 54 | - can handle various requests (messages) 55 | 56 | Consider the following server: 57 | 58 | ```ex 59 | defmodule ExampleServer do 60 | # Called the `interface` function that is used by clients to start 61 | # the server process 62 | def start do 63 | spawn(&loop/0) 64 | end 65 | 66 | def run_async(server_pid, query_def) do 67 | send(server_pid, {:run_query, self, query_def}) 68 | end 69 | 70 | def get_result do 71 | receive do 72 | {:query_result, result} -> result 73 | after 5000 -> 74 | {:error, :timeout} 75 | end 76 | end 77 | 78 | defp loop do 79 | receive do 80 | {:run_query, caller, query_def -> 81 | send(caller, {:query_result, run_query(query_def)}) 82 | end 83 | 84 | loop 85 | end 86 | 87 | defp run_query(query_def) do 88 | :timer.sleep(2000) 89 | 90 | "#{query_def} result" 91 | end 92 | end 93 | ``` 94 | 95 | A standard abstraction called `gen_server` (generic server) is provided to us to use, which helps out with the development of stateful server processes. 96 | -------------------------------------------------------------------------------- /front-end/frameworks/angular/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | ### Concepts 4 | 5 | - Model 6 | - View 7 | - Controller 8 | - Constructor function that creates a controller instance. Purpose is to expose variables and functionality to expressions and directives. 9 | - Can initialize in a template with the `ng-controller=""` directive inside an HTML tag. 10 | - Typically should use `ControllerName as controllerName` to save the controller to the variable `controllerName` in the current scope. 11 | - Templates 12 | - Directives 13 | - Expressions 14 | - `{{ expression | filter }}` syntax, allows you to access the scope and evalutes to a value 15 | - A `filter` formats the value of an expression for display to the user 16 | - Dependency Injection 17 | 18 | 19 | ### Tutorials 20 | 21 | Following along with [this tutorial](https://egghead.io/series/angularjs-app-from-scratch-getting-started). 22 | 23 | Should probably be using John Papa's [Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md). 24 | 25 | ### Controllers 26 | 27 | One way communciation: 28 | 29 | ```js 30 | // Controller logic 31 | angular.module('myApp', []) 32 | .controller('MainCtrl', function ($scope) { 33 | $scope.categories = [{ id: 0, name: 'Development' }]; 34 | }); 35 | ``` 36 | 37 | ```html 38 | 39 | 40 |
  • 41 | {{category.name}} 42 |
  • 43 | 44 | ``` 45 | 46 | Two-way communication: 47 | 48 | ```js 49 | // Controller logic 50 | angular.module('myApp', []) 51 | .controller('MainCtrl', function ($scope) { 52 | $scope.categories = [{ id: 0, name: 'Development' }]; 53 | $scope.setCurrentCategory = (category) => scope.currentCategory = category; 54 | }); 55 | ``` 56 | 57 | ```html 58 | 59 | 60 |
  • 61 | {{category.name}} 62 |
  • 63 | 64 | ``` 65 | 66 | ## Managing Simple States 67 | 68 | This is a simple example, but probably shouldn't be setting scope directly! 69 | 70 | ```js 71 | angular.module('myApp', []) 72 | .controller('MainCtrl', function ($scope) { 73 | $scope.categories = [{ id: 0, name: 'Development' }]; 74 | $scope.setCurrentCategory = (category) => scope.currentCategory = category; 75 | 76 | $scope.isCreating = false; 77 | $scope.isEditing = false; 78 | 79 | $scope.startCreating = function startCreating() { 80 | $scope.isCreating = true; 81 | $scope.isEditing= false; 82 | }; 83 | 84 | $scope.cancelCreating = function cancelCreating() { 85 | $scope.isCreating = false; 86 | }; 87 | 88 | $scope.startEditing = function startEditing() { 89 | $scope.isCreating = false; 90 | $scope.isEditing = true; 91 | }; 92 | 93 | $scope.cancelEditing = function cancelEditing() { 94 | $scope.isEditing = false; 95 | }; 96 | 97 | $scope.shouldShowCreating = () => $scope.currentCategory && !$scope.isEditing; 98 | $scope.shouldShowEditing = () => $scope.isEditing && !$scope.isCreating; 99 | }); 100 | ``` 101 | 102 | ```html 103 | 104 | 105 |
    106 | 107 | 108 |
    109 |
    110 | 111 | 112 |
    113 | 114 | ``` 115 | -------------------------------------------------------------------------------- /ocaml/README.md: -------------------------------------------------------------------------------- 1 | # OCaml 2 | 3 | ## Tuples 4 | 5 | Tuples are ordered collectinos of values that can each be of a different type. You create tuples by separating values by a comma. For example: 6 | 7 | ```ml 8 | # let some_tuple = (404, "Not Found");; 9 | val some_tuple : int * string 10 | ``` 11 | 12 | We can see the `*` character in the type signature, which represents the Cartesian product of the set of elements of type `t` and the set of elements of type `s`. 13 | 14 | For the mathematically inclined, the Cartesian Product, A x B, is a set defined as: 15 | 16 | ``` 17 | A x B = { (a, b) | a ∈ A and b ∈ B } 18 | ``` 19 | 20 | ### Pattern Matching 21 | 22 | Tuples are a great opportunity to leverage pattern-matching, for example: 23 | 24 | ```ml 25 | # let (code, message) = some_tuple;; 26 | val code : int = 404 27 | val message : string = "Not Found" 28 | ``` 29 | 30 | ## Lists 31 | 32 | An important distinction for lists in OCaml is that you use semicolons to separate list elements in lists rather than commas. Commas are instead used for tuples. 33 | 34 | Lists in OCaml are defined then using brackets and semicolons, like in `[1; 2; 3]`, where the brackets are just syntactic sugar for `::`. The `::` operator is right-associative, and is used for prepending the element on the left hand side onto the list on the right hand side, for example: 35 | 36 | ```ml 37 | (* Prepend one element onto a list *) 38 | # 1 :: 2 :: 3 :: [];; 39 | - : int list = [1; 2; 3] 40 | ``` 41 | 42 | We can also use the `::` operator to pattern-match and grab the head and tail of a list. 43 | 44 | ```ml 45 | let my_favorite_language languages = 46 | match languages with 47 | | head :: tail -> head 48 | | [] -> "OCaml" 49 | ``` 50 | 51 | ## Functions 52 | 53 | ### Recursive Functions 54 | 55 | We can specify that a function is recursive with the `rec` keyword. 56 | 57 | ```ml 58 | let rec sum list = 59 | match list with 60 | | [] -> 0 61 | | head :: tail -> head + sum tail 62 | ``` 63 | 64 | As another example, we could have multiple match statements for a function that could remove sequential duplicates. 65 | 66 | ```ml 67 | let rec dedupe list = 68 | match list with 69 | | [] -> [] 70 | | [hd] -> [hd] 71 | | hd1 :: hd2 :: tl -> 72 | if hd1 == hd2 then dedupe (hd2 :: tl) 73 | else hd1 :: dedupe (hd2 :: tl) 74 | ``` 75 | 76 | ## Options 77 | 78 | An option is used to express a value that might or might not be present. 79 | 80 | ```ml 81 | let divide x y = 82 | if y = 0 then None else Some (x/y);; 83 | ``` 84 | 85 | Where `None` and `Some` are constructors that let you build optional values. Options can be thought of as specialized lists that can only have zero or one elements. 86 | 87 | ## Records & Variants 88 | 89 | OCaml allows us to define new data types with the `type` keyword. Imagine we wanted to represent a single point in a 2d plane: 90 | 91 | ```ml 92 | type point = { x : float; y : float };; 93 | ``` 94 | 95 | In this case, `point` is a `Record` type and can be defined by doing the following: 96 | 97 | ```ml 98 | let p = { x = 3.; y = -4. };; 99 | ``` 100 | 101 | And we access the contents of the record by using pattern matching 102 | 103 | ```ml 104 | let magnitude { x = x_pos; y = y_pos } = 105 | sqrt (x_pos ** 2. +. y_pos ** 2.);; 106 | ``` 107 | 108 | This format also has a shorthand, called field punning, where we could just instead write: 109 | 110 | ```ml 111 | let magnitude { x; y } = sqrt (x ** 2. +. y ** 2.);; 112 | ``` 113 | 114 | ## Variant Type 115 | 116 | If we had a case where we wanted to create a union of types, we would use a variant type. 117 | 118 | ```ml 119 | type log = { message: string; timestamp: int };; 120 | type action = { name: string; occurences: int };; 121 | 122 | type metric = 123 | | Log of log 124 | | Action of action 125 | ``` 126 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/fiber/ReactFiberUpdateQueue.md: -------------------------------------------------------------------------------- 1 | # `ReactFiberUpdateQueue` 2 | 3 | ## Types 4 | 5 | #### `type UpdateQueue` 6 | 7 | The `UpdateQueue` is a Singly Linked-List of updates. Whenever we need to schedule an update, it's added to the queue of the current fiber and work-in-progress fiber. 8 | 9 | During reconciliation, updates are removed from the WIP Fiber, but they remain on the current fiber. 10 | 11 | Key Notes: 12 | 13 | - The WIP Queue is always a subset of the Current Queue 14 | - When a tree is committed, the WIP Queue becomes the Current Queue 15 | 16 | ## Methods 17 | 18 | #### `ensureUpdateQueue(fiber: Fiber): UpdateQueue` 19 | 20 | Just checks if we already have `updateQueue` defined on the given `fiber`. If so, return it. Otherwise, construct a new `UpdateQueue` depending on if we're in `__DEV__` or not. 21 | 22 | #### `insertUpdate(fiber: Fiber, update: Update, methodName: ?string): Update | null` 23 | 24 | ## Module 25 | 26 | This module imports the following modules: 27 | 28 | ```js 29 | const { 30 | Callback: CallbackEffect 31 | } = require('ReactTypeOfSideEffect'); 32 | const { 33 | NoWork, 34 | SynchronousPriority, 35 | TaskPriority 36 | } = require('ReactPriorityLevel'); 37 | const warning = require('warning'); 38 | ``` 39 | 40 | This module imports the following types: 41 | 42 | ```js 43 | import type { Fiber } from 'ReactFiber'; 44 | import type { PriorityLevel } from 'ReactPriorityLevel'; 45 | ``` 46 | 47 | This module leverages the following local types: 48 | 49 | ```js 50 | type PartialState = $Subtype | (prevState: State, props: Props) => $Subtype; 51 | 52 | type Callback = () => void; 53 | 54 | type Update = { 55 | priorityLevel: PriorityLevel; 56 | partialState: PartialState; 57 | callback: Callback | null; 58 | isReplace: boolean; 59 | isForced: boolean; 60 | isTopLevelUnmount: boolean; 61 | next: Update | null; 62 | }; 63 | 64 | // Singly linked-list of updates. When an update is scheduled, it is added to 65 | // the queue of the current fiber and the work-in-progress fiber. The two queues 66 | // are separate but they share a persistent structure. 67 | // 68 | // During reconciliation, updates are removed from the work-in-progress fiber, 69 | // but they remain on the current fiber. That ensures that if a work-in-progress 70 | // is aborted, the aborted updates are recovered by cloning from current. 71 | // 72 | // The work-in-progress queue is always a subset of the current queue. 73 | // 74 | // When the tree is committed, the work-in-progress becomes the current. 75 | type UpdateQueue = { 76 | first: Update | null; 77 | last: Update | null; 78 | hasForceUpdate: boolean; 79 | 80 | // Dev only 81 | isProcessing?: boolean; 82 | }; 83 | ``` 84 | 85 | Finally, this module exposes the following exports: 86 | 87 | ```js 88 | exports.cloneUpdateQueue = cloneUpdateQueue; 89 | exports.addUpdate = addUpdate; 90 | exports.addReplaceUpdate = addReplaceUpdate; 91 | exports.addForceUpdate = addForceUpdate; 92 | exports.getPendingPriority = getPendingPriority; 93 | exports.addTopLevelUpdate = addTopLevelUpdate; 94 | exports.beginUpdateQueue = beginUpdateQueue; 95 | exports.commitCallbacks = commitCallbacks; 96 | ``` 97 | 98 | And exports the following types: 99 | 100 | ```js 101 | // Singly linked-list of updates. When an update is scheduled, it is added to 102 | // the queue of the current fiber and the work-in-progress fiber. The two queues 103 | // are separate but they share a persistent structure. 104 | // 105 | // During reconciliation, updates are removed from the work-in-progress fiber, 106 | // but they remain on the current fiber. That ensures that if a work-in-progress 107 | // is aborted, the aborted updates are recovered by cloning from current. 108 | // 109 | // The work-in-progress queue is always a subset of the current queue. 110 | // 111 | // When the tree is committed, the work-in-progress becomes the current. 112 | export type UpdateQueue = { 113 | first: Update | null; 114 | last: Update | null; 115 | hasForceUpdate: boolean // Dev only 116 | isProcessing?: boolean; 117 | }; 118 | ``` 119 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/noop/README.md: -------------------------------------------------------------------------------- 1 | # Noop Renderer 2 | 3 | > This is a renderer of React that doesn't have a render target output. It is useful to demonstrate the internals of the reconciler in isolation and for testing semantics of reconciliation separate from the host environment. 4 | 5 | This file contains two major objects defined in this file, `NoopRenderer` and `ReactNoop`. 6 | 7 | `ReactNoop` is the default export. 8 | 9 | The important types defined in this module are: 10 | 11 | ```js 12 | type Container = { 13 | rootID: string, 14 | children: Array 15 | }; 16 | ``` 17 | 18 | ```js 19 | type Props = { 20 | prop: any 21 | }; 22 | ``` 23 | 24 | ```js 25 | type Instance = {| 26 | type: string, 27 | id: number, 28 | children: Array, 29 | prop: any 30 | |}; 31 | ``` 32 | 33 | ```js 34 | type TextInstance = {| 35 | text: string, 36 | id: number 37 | |}; 38 | ``` 39 | 40 | _Note: If you're wondering what `{| |}` stands for, it corresponds to Flow's [exact object types](https://github.com/facebook/flow/releases/tag/v0.32.0)_ 41 | 42 | ## `NoopRenderer` 43 | 44 | `NoopRenderer` makes a call to [`ReactFiberReconclier`](https://github.com/joshblack/notes/blob/master/front-end/frameworks/react/renderers/shared/fiber/ReactFiberReconciler.md), which exposes a function that takes in a `HostConfig` type and returns a `Reconciler`. 45 | 46 | ## `ReactNoop` 47 | 48 | `ReactNoop` is what the module exports by default, and provides a way for core contribuotrs to render a Tree of Components without having to use a Host implementation (like the DOM). 49 | 50 | Internally, the module leverages two maps for keeping track of `rootContainers` and `roots`. 51 | 52 | - `ReactNoop#getChildren(rootID: string)`: Accesses the `rootContainers` map for the given `rootID` and returns it's children if the container exists. Otherwise, return null. 53 | - `ReactNoop#render(element: ReactElement, callback: ?Function)`: Shortcut for testing a single root, basically is a proxy call to `ReactNoop#renderToRootWithID` passing in the given element, and a `DEFAULT_ROOT_ID` constant defined internally. 54 | - `ReactNoop#renderToRootWithID(element: ReactElement, rootID: string, callback: ?Function)`: Tries to retrieve the `root` value for the given `rootID` in the `roots` Map. We then branch to the following conditions: 55 | - If there is no root: 56 | - Create a `container` with the shape: `type Container = {| rootID: string, children: Array |}` 57 | - Set the key `rootID` with the value `container` in the `rootContainers` Map 58 | - Create the `root` by calling to `NoopRenderer#createContainer` by passing in the new `container` 59 | - Update the `roots` Map by adding the given `rootID` key with value `root` 60 | - Call `NoopRenderer#updateContainer` with the given `element`, the existing `root`, `null`, and the optional `callback`. 61 | - `ReactNoop#unmountRootWithID(rootID: string)`: Find the given `root` by looking up the value in the `roots` Map. If there is a root, call `NoopRenderer#updateContainer` to set it's value to null, and in the callback remove the node from the `roots` and `rootContainers` Maps. 62 | 63 | ## Module 64 | 65 | This module imports the following modules: 66 | 67 | ```js 68 | var ReactFiberReconciler = require('ReactFiberReconciler'); 69 | var ReactInstanceMap = require('ReactInstanceMap'); 70 | var { 71 | AnimationPriority 72 | } = require('ReactPriorityLevel'); 73 | var emptyObject = require('emptyObject'); 74 | ``` 75 | 76 | This module imports the following types: 77 | 78 | ```js 79 | import type { Fiber } from 'ReactFiber'; 80 | import type { UpdateQueue } from 'ReactFiberUpdateQueue'; 81 | ``` 82 | 83 | This module leverages the following local types: 84 | 85 | ```js 86 | type Container = { 87 | rootID: string; 88 | children: Array; 89 | }; 90 | type Props = { 91 | prop: any 92 | }; 93 | type Instance = {| 94 | type: string; 95 | id: number; 96 | children: Array; 97 | prop: any; 98 | |}; 99 | type TextInstance = {| 100 | text: string; 101 | id: number; 102 | |}; 103 | ``` 104 | 105 | Finally, this module exposes the following exports: 106 | 107 | ```js 108 | ReactNoop 109 | ``` 110 | -------------------------------------------------------------------------------- /front-end/frameworks/react/README.md: -------------------------------------------------------------------------------- 1 | # React (Fiber) 2 | 3 | Relevant Links: 4 | 5 | - [Fiber Principles: Contributing to Fiber](https://github.com/facebook/react/issues/7942) 6 | 7 | This section contains as many notes as possible on React's new Fiber renderer. It looks to mirror the React project structure as closely as possible, replacing the files with `.md` extensions versus `.js`. 8 | 9 | ## Terminology 10 | 11 | _Take from Andrew Clark's talk: [What's Next for React](https://www.youtube.com/watch?v=aV1271hd9ew)_ 12 | 13 | | Stack frame | Fiber | 14 | |-------------|-------| 15 | | subroutine (function) | component type | 16 | | body (nested function calls) | children | 17 | | return address | parent component | 18 | | arguments | props | 19 | | return value | DOM Elements | 20 | 21 | ## History 22 | 23 | ### [Outline for new Reconciler Infrastructure](https://github.com/facebook/react/pull/6690) 24 | 25 | _[Dan Abramov's Explanation for changes](https://github.com/facebook/react/pull/6690#issuecomment-217130167)_ 26 | 27 | Really interesting PR that introduceds the initial foundation for the new reconciler infrastructure. You can see that the types of work are a subset of what they become in the actual implementation: 28 | 29 | ```js 30 | var TypesOfWork = { 31 | FunctionalComponent: 1, 32 | ClassComponent: 2, 33 | NativeComponent: 3, 34 | }; 35 | ``` 36 | 37 | There is an idea for a `StateNode` that is simply an object with a `next` field that could return another `StateNode`. 38 | 39 | ```js 40 | type StateNode = { 41 | next: ?{ [key: string]: StateNode }, 42 | }; 43 | 44 | module.exports = function() : StateNode { 45 | return { 46 | next: null, 47 | }; 48 | }; 49 | ``` 50 | 51 | There is the intorduction of the `ReactFiberReconciler` file, which exposes are first `HostConfig` and `Reconciler` types. 52 | 53 | ```js 54 | export type HostConfig = { 55 | createHostInstance(element : ReactHostElement) : I, 56 | scheduleHighPriCallback(callback : () => void) : void, 57 | scheduleLowPriCallback(callback : (deadline : Deadline) => void) : void 58 | }; 59 | 60 | export type Reconciler = { 61 | mountNewRoot(element : ReactElement) : OpaqueID; 62 | }; 63 | ``` 64 | 65 | It's cool to see the contract still being held where `ReactFiberReconciler` exports a function that takes in a `HostConfig` and returns a `Reconciler`. 66 | 67 | There's also the introduction of `performUnitOfWork`, taking in a `Fiber` and possibly returning it (if the `tag` of the `fiber` is defined). 68 | 69 | And, finally, there is the first look at the definition of a `Fiber`: 70 | 71 | ```js 72 | export type Fiber = { 73 | tag: number, 74 | 75 | parent: ?Fiber, 76 | child: ?Fiber, 77 | sibling: ?Fiber, 78 | 79 | input: ?Object, 80 | output: ?Object, 81 | 82 | handler: EffectHandler, 83 | handlerTag: EffectTag, 84 | 85 | hasPendingChanges: bool, 86 | 87 | stateNode: StateNode, 88 | }; 89 | ``` 90 | 91 | ### [Fiber Principles: Contributing to Fiber](https://github.com/facebook/react/issues/7942) 92 | 93 | ### [[Fiber] Umbrella for remaining features & bugs](https://github.com/facebook/react/issues/7925) 94 | 95 | _[Dan Abramov explains how to help](https://github.com/facebook/react/issues/7925#issuecomment-259258900)_ 96 | 97 | ## Types 98 | 99 | #### `ReactEmpty` 100 | 101 | ```js 102 | type ReactEmpty: null | void | boolean; 103 | ``` 104 | 105 | #### `ReactText` 106 | 107 | ```js 108 | type ReactText: string | number; 109 | ``` 110 | 111 | #### `ReactNodeList` 112 | 113 | ```js 114 | type ReactNodeList = ReactEmpty | ReactNode; 115 | ``` 116 | 117 | #### `ReactFragment` 118 | 119 | ```js 120 | type ReactFragment = ReactEmpty | Iterable; 121 | ``` 122 | 123 | #### `ReactYield` 124 | 125 | ```js 126 | type ReactYield = { 127 | $$typeof: Symbol | number, 128 | key: null | string, 129 | props: Object, 130 | continutation: mixed 131 | }; 132 | ``` 133 | 134 | #### `ReactCoroutine` 135 | 136 | ```js 137 | export type ReactCoroutine = { 138 | $$typeof: Symbol | number, 139 | key: null | string, 140 | children: any, 141 | // This should be a more specific CoroutineHandler 142 | handler: (props: any, yields: Array) => ReactNodeList, 143 | props: any, 144 | }; 145 | ``` 146 | 147 | #### `ReactPortal` 148 | 149 | ```js 150 | export type ReactPortal = { 151 | $$typeof: Symbol | number, 152 | key: null | string, 153 | containerInfo: any, 154 | children : ReactNodeList, 155 | implementation: any, 156 | }; 157 | ``` 158 | 159 | #### `ReactNode` 160 | 161 | ```js 162 | type ReactNode = 163 | ReactElement | 164 | ReactCoroutine | 165 | ReactYield | 166 | ReactPortal | 167 | ReactText | 168 | ReactFragment; 169 | ``` 170 | 171 | ## Resources 172 | 173 | - [React Fiber Architecture](https://github.com/acdlite/react-fiber-architecture) 174 | -------------------------------------------------------------------------------- /agile/frankenbuilds.md: -------------------------------------------------------------------------------- 1 | # Frankenbuilds - If Agile is so good, why are our Products so bad? 2 | 3 | > Gabrielle Benefield, [Source](https://www.youtube.com/watch?v=2JNXx8VdbAE) 4 | 5 | - build outcomes over output, We need to build value 6 | - Target Outcome Frameworks 7 | - Velocity, and other estimated measures, are all just getting in the way of finding out our outcomes 8 | - How to get started 9 | - Understand what's really going on 10 | - Lean is about reducing waste, making things more efficient, and LEARNING! 11 | - Checkout: a3 thinking from Toyota, systemic reasons and why we have problems and causes for things 12 | - Become the method actor of user experience 13 | - Never ask your users what they want, and _never_ ask the developers what they think the user wants 14 | - Get out of your chair and find out what they need 15 | - IDEO: We create empathy, we build personas to remind us that real people use our products 16 | - Each user has a goal, a job to get done 17 | - Figure out what it is that they want to do, iterate to make that process better and better 18 | - Find core jobs, make them as easy as possible to do 19 | - Once you know where you are, figure out where you want to be 20 | - Do deep thinking, value stream mapping, 5 y's, 21 | - Impact mapping: choose the right outcomes by measuring the severity of the problem or size of the opportunity 22 | - 80/20 thinking caps (20% of the features is used 80% of the time) 23 | - Agile has a great way to get products out quickly, need to find the right 20 to build 24 | - Understand where is the greatest upside 25 | - Set target outcomes 26 | - Target outcomes are the poke yoke of product development 27 | - They make it easy to build the right thing and hard to build the wrong thing (think floppy disks, only one way to put it in a computer) 28 | - Helps us tell which features to put in, and which features not to build 29 | - We can build features quickly, we need to know which ones are the right ones to build 30 | - Target outcomes need to be clear and measurable 31 | - Need a good baseline, need data to help determine that baseline 32 | - If you don't measure how will you know when you get there? 33 | - Can you quantify everything? 34 | - We're not measuring to get the most precise number 35 | - We're trying to get down to a level of understanding where it's easy to do the right thing, hard to do the wrong thing 36 | - Target outcomes set a direction, and th ere are many ways to achieve it 37 | - Options Thinking 38 | - When you plan based on outputs, you commit to a certain future 39 | - This is what we think we're going to do, danger is that we're defining it up-front, it has a life of it's own 40 | - Stop pretending you can see the future and _create options_ 41 | - Have multiple ideas 42 | - Keep your options open, be ready to execute rapidly 43 | - Make decisions as reversible as possible, and irreversible decisions as late as possibly 44 | - It's about arrival, not surival, of the fittest. Surivival is the slowest form of suicide 45 | - It's the people who can get to market with the right product the quickest, not the ones who can just suriveve 46 | - Outcomes and options are fractal 47 | - Reach, engagement, for example. Should align to every area of development right down to the quality of your systems 48 | - Each one leads to another 49 | - It's more tree-based, than a linear product backlog (very tactical thinking, keep hacking things together and hoping for a good result) 50 | - There are no product requirements, they are product guesses. Stop guessing and start testing 51 | - Run multiple options fast, make the unknowns known 52 | - Set based design, run options concurrently on the mark 53 | - Get in front of your users early and often 54 | - Seeing is believing, research is too important to leave up to the researches 55 | - Yahoo used to show developers and bring them on field trips to show them that people don't use it 56 | - Ignore your mother, be fast, dirty, and cheap 57 | - Give away free lunch every friday and have people use your product, get feedback! 58 | - More features are actually a problem, remove the inessentials so the essentials can speak 59 | - When the iPhone came out, they had 40% less of the features than their competitors 60 | - The game is to hit the target with as few bullets as possible 61 | - Velocity, cycle time measures, are all for throughput. Tells developers to build as much as possible. 62 | - Set a game target, we need to get here quickly with _as few features as possible_ 63 | - Minimum viable and not maximum potential 64 | - Measure as you go to check and see if you're in the right direction 65 | - Setup automated metric frameworks 66 | - Do you have usage statistics, 67 | - If your metrics lag, you lag 68 | - Multivariate testing, skip testing in a room and send it out 69 | - Metrics gathering is meant for everyone, especially developers 70 | - Transparency is key, share the data with the entire development team 71 | - Progress indicators tell if you you're on track 72 | - The most important thing to see is not burndown charts, it's about seeing if target outcomes validate the investment 73 | - How do we know if we've succeeded? 74 | - If we are not hitting the target outcomes, adapt 75 | - Agilistas are killing the planet 76 | - When you use the machine gun approach you build more features fast 77 | - The more featuers you build the more resources you consume 78 | - Save the features, save the planet 79 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/fiber/ReactFiberReconciler.md: -------------------------------------------------------------------------------- 1 | # `ReactFiberReconciler` 2 | 3 | It seems that `ReactFiberReconciler` exposes an important type called `HostConfig`, and exports a function that takes in a `HostConfig` and returns a `Reconciler`. 4 | 5 | `HostConfig` is parametrized by the following type parameters: 6 | 7 | - `T`: Type 8 | - `P`: Props 9 | - `I`: Instance 10 | - `TI`: Text Instance 11 | - `C`: Container 12 | - `CX`: Context 13 | 14 | #### `scheduleTopLevelUpdate(current: Fiber, element: ReactNodeList, callback: ?Function)` 15 | 16 | ## Module 17 | 18 | This module imports the following modules: 19 | 20 | ```js 21 | var { 22 | addTopLevelUpdate 23 | } = require('ReactFiberUpdateQueue'); 24 | var { 25 | findCurrentUnmaskedContext, 26 | isContextProvider, 27 | processChildContext 28 | } = require('ReactFiberContext'); 29 | var { 30 | createFiberRoot 31 | } = require('ReactFiberRoot'); 32 | var ReactFiberScheduler = require('ReactFiberScheduler'); 33 | var ReactFiberInstrumentation = require('ReactFiberInstrumentation'); 34 | var { 35 | findCurrentHostFiber 36 | } = require('ReactFiberTreeReflection'); 37 | var getContextForSubtree = require('getContextForSubtree'); 38 | ``` 39 | 40 | This module imports the following types: 41 | 42 | ```js 43 | import type { Fiber } from 'ReactFiber'; 44 | import type { FiberRoot } from 'ReactFiberRoot'; 45 | import type { PriorityLevel } from 'ReactPriorityLevel'; 46 | import type { ReactNodeList } from 'ReactTypes'; 47 | ``` 48 | 49 | This module leverages the following local types: 50 | 51 | ```js 52 | type Deadline = { 53 | timeRemaining: () => number 54 | }; 55 | type OpaqueNode = Fiber; 56 | type HostConfig = { 57 | getRootHostContext: (rootContainerInstance: C) => CX; 58 | getChildHostContext: (parentHostContext: CX, type: T) => CX; 59 | createInstance: (type: T, props: P, rootContainerInstance: C, hostContext: CX, internalInstanceHandle: OpaqueNode) => I; 60 | appendInitialChild: (parentInstance: I, child: I | TI) => void; 61 | finalizeInitialChildren: (parentInstance: I, type: T, props: P, rootContainerInstance: C) => boolean; 62 | prepareUpdate: (instance: I, type: T, oldProps: P, newProps: P, hostContext: CX) => boolean; 63 | commitUpdate: (instance: I, type: T, oldProps: P, newProps: P, rootContainerInstance: C, internalInstanceHandle: OpaqueNode) => void; 64 | commitMount: (instance: I, type: T, newProps: P, rootContainerInstance: C, internalInstanceHandle: OpaqueNode) => void; 65 | shouldSetTextContent: (props: P) => boolean; 66 | resetTextContent: (instance: I) => void; 67 | createTextInstance: (text: string, rootContainerInstance: C, hostContext: CX, internalInstanceHandle: OpaqueNode) => TI; 68 | commitTextUpdate: (textInstance: TI, oldText: string, newText: string) => void; 69 | appendChild: (parentInstance: I | C, child: I | TI) => void; 70 | insertBefore: (parentInstance: I | C, child: I | TI, beforeChild: I | TI) => void; 71 | removeChild: (parentInstance: I | C, child: I | TI) => void; 72 | scheduleAnimationCallback: (callback: () => void) => void; 73 | scheduleDeferredCallback: (callback: (deadline: Deadline) => void) => void; 74 | prepareForCommit: () => void; 75 | resetAfterCommit: () => void; 76 | useSyncScheduling?: boolean; 77 | }; 78 | type Reconciler = { 79 | createContainer: (containerInfo: C) => OpaqueNode; 80 | updateContainer: (element: ReactNodeList, container: OpaqueNode, parentComponent: ?ReactComponent) => void; 81 | performWithPriority: (priorityLevel: PriorityLevel, fn: Function) => void /* eslint-disable no-undef */ // FIXME: ESLint complains about type parameter 82 | ; 83 | batchedUpdates: (fn: () => A) => A; 84 | syncUpdates: (fn: () => A) => A; 85 | deferredUpdates: (fn: () => A) => A /* eslint-enable no-undef */ // Used to extract the return value from the initial render. Legacy API. 86 | ; 87 | getPublicRootInstance: (container: OpaqueNode) => ReactComponent | TI | I | null // Use for findDOMNode/findHostNode. Legacy API. 88 | ; 89 | findHostInstance: (component: Fiber) => I | TI | null; 90 | }; 91 | ``` 92 | 93 | Finally, this module exposes the following exports: 94 | 95 | ```js 96 | function (config: HostConfig): Reconciler { 97 | var { 98 | scheduleUpdate, 99 | getPriorityContext, 100 | performWithPriority, 101 | batchedUpdates, 102 | syncUpdates, 103 | deferredUpdates 104 | } = ReactFiberScheduler(config); 105 | 106 | function scheduleTopLevelUpdate(current: Fiber, element: ReactNodeList, callback: ?Function) { 107 | const priorityLevel = getPriorityContext(); 108 | const nextState = { 109 | element 110 | }; 111 | addTopLevelUpdate(current, nextState, callback || null, priorityLevel); 112 | scheduleUpdate(current, priorityLevel); 113 | } 114 | 115 | return { 116 | createContainer(containerInfo: C): OpaqueNode { 117 | const root = createFiberRoot(containerInfo); 118 | const current = root.current; // It may seem strange that we don't return the root here, but that will 119 | // allow us to have containers that are in the middle of the tree instead 120 | // of being roots. 121 | 122 | return current; 123 | }, 124 | 125 | updateContainer(element: ReactNodeList, container: OpaqueNode, parentComponent: ?ReactComponent, callback: ?Function): void { 126 | // TODO: If this is a nested container, this won't be the root. 127 | const root: FiberRoot = (container.stateNode: any); 128 | const current = root.current; 129 | 130 | if (__DEV__) { 131 | if (ReactFiberInstrumentation.debugTool) { 132 | if (current.alternate === null) { 133 | ReactFiberInstrumentation.debugTool.onMountContainer(root); 134 | } else if (element === null) { 135 | ReactFiberInstrumentation.debugTool.onUnmountContainer(root); 136 | } else { 137 | ReactFiberInstrumentation.debugTool.onUpdateContainer(root); 138 | } 139 | } 140 | } 141 | 142 | const context = getContextForSubtree(parentComponent); 143 | 144 | if (root.context === null) { 145 | root.context = context; 146 | } else { 147 | root.pendingContext = context; 148 | } 149 | 150 | scheduleTopLevelUpdate(current, element, callback); 151 | }, 152 | 153 | performWithPriority, 154 | batchedUpdates, 155 | syncUpdates, 156 | deferredUpdates, 157 | 158 | getPublicRootInstance(container: OpaqueNode): ReactComponent | I | TI | null { 159 | const root: FiberRoot = (container.stateNode: any); 160 | const containerFiber = root.current; 161 | 162 | if (!containerFiber.child) { 163 | return null; 164 | } 165 | 166 | return containerFiber.child.stateNode; 167 | }, 168 | 169 | findHostInstance(fiber: Fiber): I | TI | null { 170 | const hostFiber = findCurrentHostFiber(fiber); 171 | 172 | if (!hostFiber) { 173 | return null; 174 | } 175 | 176 | return hostFiber.stateNode; 177 | } 178 | 179 | }; 180 | } 181 | ``` 182 | 183 | And exports the following types: 184 | 185 | ```js 186 | export type Deadline = { 187 | timeRemaining: () => number 188 | }; 189 | export type HostConfig = { 190 | getRootHostContext: (rootContainerInstance: C) => CX; 191 | getChildHostContext: (parentHostContext: CX, type: T) => CX; 192 | createInstance: (type: T, props: P, rootContainerInstance: C, hostContext: CX, internalInstanceHandle: OpaqueNode) => I; 193 | appendInitialChild: (parentInstance: I, child: I | TI) => void; 194 | finalizeInitialChildren: (parentInstance: I, type: T, props: P, rootContainerInstance: C) => boolean; 195 | prepareUpdate: (instance: I, type: T, oldProps: P, newProps: P, hostContext: CX) => boolean; 196 | commitUpdate: (instance: I, type: T, oldProps: P, newProps: P, rootContainerInstance: C, internalInstanceHandle: OpaqueNode) => void; 197 | commitMount: (instance: I, type: T, newProps: P, rootContainerInstance: C, internalInstanceHandle: OpaqueNode) => void; 198 | shouldSetTextContent: (props: P) => boolean; 199 | resetTextContent: (instance: I) => void; 200 | createTextInstance: (text: string, rootContainerInstance: C, hostContext: CX, internalInstanceHandle: OpaqueNode) => TI; 201 | commitTextUpdate: (textInstance: TI, oldText: string, newText: string) => void; 202 | appendChild: (parentInstance: I | C, child: I | TI) => void; 203 | insertBefore: (parentInstance: I | C, child: I | TI, beforeChild: I | TI) => void; 204 | removeChild: (parentInstance: I | C, child: I | TI) => void; 205 | scheduleAnimationCallback: (callback: () => void) => void; 206 | scheduleDeferredCallback: (callback: (deadline: Deadline) => void) => void; 207 | prepareForCommit: () => void; 208 | resetAfterCommit: () => void; 209 | useSyncScheduling?: boolean; 210 | }; 211 | export type Reconciler = { 212 | createContainer: (containerInfo: C) => OpaqueNode; 213 | updateContainer: (element: ReactNodeList, container: OpaqueNode, parentComponent: ?ReactComponent) => void; 214 | performWithPriority: (priorityLevel: PriorityLevel, fn: Function) => void /* eslint-disable no-undef */ // FIXME: ESLint complains about type parameter 215 | ; 216 | batchedUpdates: (fn: () => A) => A; 217 | syncUpdates: (fn: () => A) => A; 218 | deferredUpdates: (fn: () => A) => A /* eslint-enable no-undef */ // Used to extract the return value from the initial render. Legacy API. 219 | ; 220 | getPublicRootInstance: (container: OpaqueNode) => ReactComponent | TI | I | null // Use for findDOMNode/findHostNode. Legacy API. 221 | ; 222 | findHostInstance: (component: Fiber) => I | TI | null; 223 | }; 224 | ``` 225 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/fiber/ReactFiber.md: -------------------------------------------------------------------------------- 1 | # `ReactFiber` 2 | 3 | `ReactFiber` exports the `Fiber` type, as well as a variety of functions for building different kinds of Fibers. 4 | 5 | #### `createFiber(tag: TypeOfWork, key: null | string): Fiber` 6 | 7 | Given a tag and possible key, build a Fiber! 8 | 9 | #### `cloneFiber(fiber: Fiber, priorityLevel: PriorityLevel): Fiber` 10 | 11 | Used to create an alternate fiber to do work on. From the source: 12 | 13 | ```js 14 | // We clone to get a work in progress. That means that this fiber is the 15 | // current. To make it safe to reuse that fiber later on as work in progress 16 | // we need to reset its work in progress flag now. We don't have an 17 | // opportunity to do this earlier since we don't traverse the tree when 18 | // the work in progress tree becomes the current tree. 19 | // fiber.progressedPriority = NoWork; 20 | // fiber.progressedChild = null; 21 | 22 | // We use a double buffering pooling technique because we know that we'll only 23 | // ever need at most two versions of a tree. We pool the "other" unused node 24 | // that we're free to reuse. This is lazily created to avoid allocating extra 25 | // objects for things that are never updated. It also allow us to reclaim the 26 | // extra memory if needed. 27 | ``` 28 | 29 | #### `createHostRootFiber(): Fiber` 30 | 31 | Creates a Fiber with the `HostRoot` `TypeOfWork`. 32 | 33 | #### `createFiberFromElementType(type: mixed, key: null | string): Fiber` 34 | 35 | Creates a Fiber based on the given `type`, or we've been given a continutation that is already a fiber. 36 | 37 | As a result, we branch based loosely off of the given `type` into the following scenairos: 38 | 39 | - if `typeof type === 'function'`: 40 | - We use a `shouldConstruct` utility to decide whether we've been given a `ClassComponent` or `IndeterminateComponent` and build a fiber with the corresponding `tag`/`TypeOfWork`. 41 | - if `typeof type === 'string'`: 42 | - We create a Fiber with the `HostComponent` tag 43 | - if `typeof type === 'object' && type !== null && typeof type.tag === 'number'`: 44 | - Assumed to be a continuation and is a fiber already 45 | - else: 46 | - We haven't gotten a valid Element type, warn if in `__DEV__` 47 | 48 | #### `createFiberFromElement(element: ReactElement, priorityLevel: PriorityLevel): Fiber` 49 | 50 | Construct a fiber using `createFiberFromElementType`, and add `element.props` to the fiber's `fiber.pendingProps` field, as well as set the priority level on the fiber. 51 | 52 | #### `createFiberFromFragment(elements: ReactFragment, priorityLevel: PriorityLevel): Fiber` 53 | 54 | Constructs a fiber with `Fragment` as the `tag`. Sets the fiber's `pendingProps` property to `elements`, and sets its `pendingWorkPriority` property as well. 55 | 56 | #### `createFiberFromText(content: string, priorityLevel: PriorityLevel): Fiber` 57 | 58 | Creates a fiber with the `HostText` `tag`. Set `pendingProps` to `content`, and `pendingWorkPriority` to `priorityLevel`. 59 | 60 | ## Module 61 | 62 | This module imports the following modules: 63 | 64 | ```js 65 | var ReactTypeOfWork = require('ReactTypeOfWork'); 66 | var { 67 | NoWork 68 | } = require('ReactPriorityLevel'); 69 | var { 70 | NoEffect 71 | } = require('ReactTypeOfSideEffect'); 72 | var { 73 | cloneUpdateQueue 74 | } = require('ReactFiberUpdateQueue'); 75 | var invariant = require('invariant'); 76 | var { 77 | getCurrentFiberOwnerName 78 | } = require('ReactDebugCurrentFiber'); 79 | ``` 80 | 81 | This module imports the following types: 82 | 83 | ```js 84 | import type { ReactElement, Source } from 'ReactElementType'; 85 | import type { ReactInstance, DebugID } from 'ReactInstanceType'; 86 | import type { ReactFragment } from 'ReactTypes'; 87 | import type { ReactCoroutine, ReactYield } from 'ReactCoroutine'; 88 | import type { ReactPortal } from 'ReactPortal'; 89 | import type { TypeOfWork } from 'ReactTypeOfWork'; 90 | import type { TypeOfSideEffect } from 'ReactTypeOfSideEffect'; 91 | import type { PriorityLevel } from 'ReactPriorityLevel'; 92 | import type { UpdateQueue } from 'ReactFiberUpdateQueue'; 93 | ``` 94 | 95 | Finally, this module exposes the following exports: 96 | 97 | ```js 98 | // This is used to create an alternate fiber to do work on. 99 | // TODO: Rename to createWorkInProgressFiber or something like that. 100 | exports.cloneFiber = function (fiber: Fiber, priorityLevel: PriorityLevel): Fiber 101 | 102 | exports.createHostRootFiber = function (): Fiber 103 | 104 | exports.createFiberFromElement = function (element: ReactElement, priorityLevel: PriorityLevel): Fiber 105 | 106 | exports.createFiberFromFragment = function (elements: ReactFragment, priorityLevel: PriorityLevel): Fiber 107 | 108 | exports.createFiberFromText = function (content: string, priorityLevel: PriorityLevel): Fiber 109 | 110 | exports.createFiberFromElementType = createFiberFromElementType; 111 | 112 | exports.createFiberFromCoroutine = function (coroutine: ReactCoroutine, priorityLevel: PriorityLevel): Fiber 113 | 114 | exports.createFiberFromYield = function (yieldNode: ReactYield, priorityLevel: PriorityLevel): Fiber 115 | 116 | exports.createFiberFromPortal = function (portal: ReactPortal, priorityLevel: PriorityLevel): Fiber 117 | ``` 118 | 119 | And exports the following types: 120 | 121 | ```js 122 | // A Fiber is work on a Component that needs to be done or was done. There can 123 | // be more than one per component. 124 | export type Fiber = { 125 | // __DEV__ only 126 | _debugID ?: DebugID, 127 | _debugSource ?: Source | null, 128 | _debugOwner ?: Fiber | ReactInstance | null, // Stack compatible 129 | 130 | // These first fields are conceptually members of an Instance. This used to 131 | // be split into a separate type and intersected with the other Fiber fields, 132 | // but until Flow fixes its intersection bugs, we've merged them into a 133 | // single type. 134 | 135 | // An Instance is shared between all versions of a component. We can easily 136 | // break this out into a separate object to avoid copying so much to the 137 | // alternate versions of the tree. We put this on a single object for now to 138 | // minimize the number of objects created during the initial render. 139 | 140 | // Tag identifying the type of fiber. 141 | tag: TypeOfWork, 142 | 143 | // Unique identifier of this child. 144 | key: null | string, 145 | 146 | // The function/class/module associated with this fiber. 147 | type: any, 148 | 149 | // The local state associated with this fiber. 150 | stateNode: any, 151 | 152 | // Conceptual aliases 153 | // parent : Instance -> return The parent happens to be the same as the 154 | // return fiber since we've merged the fiber and instance. 155 | 156 | // Remaining fields belong to Fiber 157 | 158 | // The Fiber to return to after finishing processing this one. 159 | // This is effectively the parent, but there can be multiple parents (two) 160 | // so this is only the parent of the thing we're currently processing. 161 | // It is conceptually the same as the return address of a stack frame. 162 | return: ?Fiber, 163 | 164 | // Singly Linked List Tree Structure. 165 | child: ?Fiber, 166 | sibling: ?Fiber, 167 | index: number, 168 | 169 | // The ref last used to attach this node. 170 | // I'll avoid adding an owner field for prod and model that as functions. 171 | ref: null | (((handle : ?Object) => void) & { _stringRef: ?string }), 172 | 173 | // Input is the data coming into process this fiber. Arguments. Props. 174 | pendingProps: any, // This type will be more specific once we overload the tag. 175 | // TODO: I think that there is a way to merge pendingProps and memoizedProps. 176 | memoizedProps: any, // The props used to create the output. 177 | 178 | // A queue of state updates and callbacks. 179 | updateQueue: UpdateQueue | null, 180 | // A list of callbacks that should be called during the next commit. 181 | callbackList: UpdateQueue | null, 182 | // The state used to create the output 183 | memoizedState: any, 184 | 185 | // Effect 186 | effectTag: TypeOfSideEffect, 187 | 188 | // Singly linked list fast path to the next fiber with side-effects. 189 | nextEffect: ?Fiber, 190 | 191 | // The first and last fiber with side-effect within this subtree. This allows 192 | // us to reuse a slice of the linked list when we reuse the work done within 193 | // this fiber. 194 | firstEffect: ?Fiber, 195 | lastEffect: ?Fiber, 196 | 197 | // This will be used to quickly determine if a subtree has no pending changes. 198 | pendingWorkPriority: PriorityLevel, 199 | 200 | // This value represents the priority level that was last used to process this 201 | // component. This indicates whether it is better to continue from the 202 | // progressed work or if it is better to continue from the current state. 203 | progressedPriority: PriorityLevel, 204 | 205 | // If work bails out on a Fiber that already had some work started at a lower 206 | // priority, then we need to store the progressed work somewhere. This holds 207 | // the started child set until we need to get back to working on it. It may 208 | // or may not be the same as the "current" child. 209 | progressedChild: ?Fiber, 210 | 211 | // When we reconcile children onto progressedChild it is possible that we have 212 | // to delete some child fibers. We need to keep track of this side-effects so 213 | // that if we continue later on, we have to include those effects. Deletions 214 | // are added in the reverse order from sibling pointers. 215 | progressedFirstDeletion: ?Fiber, 216 | progressedLastDeletion: ?Fiber, 217 | 218 | // This is a pooled version of a Fiber. Every fiber that gets updated will 219 | // eventually have a pair. There are cases when we can clean up pairs to save 220 | // memory if we need to. 221 | alternate: ?Fiber, 222 | 223 | // Conceptual aliases 224 | // workInProgress : Fiber -> alternate The alternate used for reuse happens 225 | // to be the same as work in progress. 226 | }; 227 | ``` 228 | -------------------------------------------------------------------------------- /front-end/frameworks/react/renderers/shared/fiber/createContainer.md: -------------------------------------------------------------------------------- 1 | # `createContainer` 2 | 3 | _Note: this isn't a file located in the library, just are existing notes for understanding the `createContainer` command from a `Reconciler`._ 4 | 5 | ### Initial Container 6 | 7 | ```js 8 | { 9 | tag: 3, 10 | key: null, 11 | type: null, 12 | stateNode: { 13 | current: [Circular], 14 | containerInfo: { rootID: '', children: [] }, 15 | isScheduled: false, 16 | nextScheduledRoot: null, 17 | callbackList: null, 18 | context: null, 19 | pendingContext: null 20 | }, 21 | return: null, 22 | child: null, 23 | sibling: null, 24 | index: 0, 25 | ref: null, 26 | pendingProps: null, 27 | memoizedProps: null, 28 | updateQueue: null, 29 | callbackList: null, 30 | memoizedState: null, 31 | effectTag: 0, 32 | nextEffect: null, 33 | firstEffect: null, 34 | lastEffect: null, 35 | pendingWorkPriority: 0, 36 | progressedPriority: 0, 37 | progressedChild: null, 38 | progressedFirstDeletion: null, 39 | progressedLastDeletion: null, 40 | alternate: null, 41 | _debugID: 1, 42 | _debugSource: null, 43 | _debugOwner: null 44 | } 45 | ``` 46 | 47 | ### Updated Container (with work scheduled) 48 | 49 | ```js 50 | { 51 | tag: 3, 52 | key: null, 53 | type: null, 54 | stateNode: { 55 | current: { 56 | tag: 3, 57 | key: null, 58 | type: null, 59 | stateNode: [Circular], 60 | return: null, 61 | child: [Object], 62 | sibling: null, 63 | index: 0, 64 | ref: null, 65 | pendingProps: null, 66 | memoizedProps: null, 67 | updateQueue: null, 68 | callbackList: null, 69 | memoizedState: [Object], 70 | effectTag: 0, 71 | nextEffect: null, 72 | firstEffect: [Object], 73 | lastEffect: [Object], 74 | pendingWorkPriority: 0, 75 | progressedPriority: 5, 76 | progressedChild: [Object], 77 | progressedFirstDeletion: null, 78 | progressedLastDeletion: null, 79 | alternate: [Circular], 80 | _debugID: 1, 81 | _debugSource: null, 82 | _debugOwner: null 83 | }, 84 | containerInfo: { rootID: '', children: [Object] }, 85 | isScheduled: false, 86 | nextScheduledRoot: null, 87 | callbackList: null, 88 | context: {}, 89 | pendingContext: null 90 | }, 91 | return: null, 92 | child: null, 93 | sibling: null, 94 | index: 0, 95 | ref: null, 96 | pendingProps: null, 97 | memoizedProps: null, 98 | updateQueue: 99 | { first: 100 | { priorityLevel: 5, 101 | partialState: [Object], 102 | callback: null, 103 | isReplace: false, 104 | isForced: false, 105 | isTopLevelUnmount: false, 106 | next: null }, 107 | last: 108 | { priorityLevel: 5, 109 | partialState: [Object], 110 | callback: null, 111 | isReplace: false, 112 | isForced: false, 113 | isTopLevelUnmount: false, 114 | next: null }, 115 | hasForceUpdate: false, 116 | isProcessing: false }, 117 | callbackList: null, 118 | memoizedState: null, 119 | effectTag: 0, 120 | nextEffect: null, 121 | firstEffect: null, 122 | lastEffect: null, 123 | pendingWorkPriority: 5, 124 | progressedPriority: 5, 125 | progressedChild: 126 | { tag: 1, 127 | key: null, 128 | type: [Function: Text], 129 | stateNode: null, 130 | return: 131 | { tag: 3, 132 | key: null, 133 | type: null, 134 | stateNode: [Object], 135 | return: null, 136 | child: [Circular], 137 | sibling: null, 138 | index: 0, 139 | ref: null, 140 | pendingProps: null, 141 | memoizedProps: null, 142 | updateQueue: null, 143 | callbackList: null, 144 | memoizedState: [Object], 145 | effectTag: 0, 146 | nextEffect: null, 147 | firstEffect: [Circular], 148 | lastEffect: [Circular], 149 | pendingWorkPriority: 0, 150 | progressedPriority: 5, 151 | progressedChild: [Circular], 152 | progressedFirstDeletion: null, 153 | progressedLastDeletion: null, 154 | alternate: [Circular], 155 | _debugID: 1, 156 | _debugSource: null, 157 | _debugOwner: null }, 158 | child: 159 | { tag: 6, 160 | key: null, 161 | type: null, 162 | stateNode: [Object], 163 | return: [Circular], 164 | child: null, 165 | sibling: null, 166 | index: 0, 167 | ref: null, 168 | pendingProps: null, 169 | memoizedProps: 'foo', 170 | updateQueue: null, 171 | callbackList: null, 172 | memoizedState: null, 173 | effectTag: 0, 174 | nextEffect: null, 175 | firstEffect: null, 176 | lastEffect: null, 177 | pendingWorkPriority: 0, 178 | progressedPriority: 0, 179 | progressedChild: null, 180 | progressedFirstDeletion: null, 181 | progressedLastDeletion: null, 182 | alternate: null, 183 | _debugID: 4, 184 | _debugSource: null, 185 | _debugOwner: null }, 186 | sibling: null, 187 | index: 0, 188 | ref: null, 189 | pendingProps: null, 190 | memoizedProps: { value: 'foo' }, 191 | updateQueue: null, 192 | callbackList: null, 193 | memoizedState: null, 194 | effectTag: 0, 195 | nextEffect: null, 196 | firstEffect: null, 197 | lastEffect: null, 198 | pendingWorkPriority: 0, 199 | progressedPriority: 5, 200 | progressedChild: 201 | { tag: 6, 202 | key: null, 203 | type: null, 204 | stateNode: [Object], 205 | return: [Circular], 206 | child: null, 207 | sibling: null, 208 | index: 0, 209 | ref: null, 210 | pendingProps: null, 211 | memoizedProps: 'foo', 212 | updateQueue: null, 213 | callbackList: null, 214 | memoizedState: null, 215 | effectTag: 0, 216 | nextEffect: null, 217 | firstEffect: null, 218 | lastEffect: null, 219 | pendingWorkPriority: 0, 220 | progressedPriority: 0, 221 | progressedChild: null, 222 | progressedFirstDeletion: null, 223 | progressedLastDeletion: null, 224 | alternate: null, 225 | _debugID: 4, 226 | _debugSource: null, 227 | _debugOwner: null }, 228 | progressedFirstDeletion: null, 229 | progressedLastDeletion: null, 230 | alternate: null, 231 | _debugID: 3, 232 | _debugSource: 233 | { fileName: 'src/renderers/shared/fiber/__tests__/ReactTopLevelText-test.js', 234 | lineNumber: 28 }, 235 | _debugOwner: null }, 236 | progressedFirstDeletion: null, 237 | progressedLastDeletion: null, 238 | alternate: 239 | { tag: 3, 240 | key: null, 241 | type: null, 242 | stateNode: 243 | { current: [Circular], 244 | containerInfo: [Object], 245 | isScheduled: false, 246 | nextScheduledRoot: null, 247 | callbackList: null, 248 | context: {}, 249 | pendingContext: null }, 250 | return: null, 251 | child: 252 | { tag: 1, 253 | key: null, 254 | type: [Function: Text], 255 | stateNode: null, 256 | return: [Circular], 257 | child: [Object], 258 | sibling: null, 259 | index: 0, 260 | ref: null, 261 | pendingProps: null, 262 | memoizedProps: [Object], 263 | updateQueue: null, 264 | callbackList: null, 265 | memoizedState: null, 266 | effectTag: 0, 267 | nextEffect: null, 268 | firstEffect: null, 269 | lastEffect: null, 270 | pendingWorkPriority: 0, 271 | progressedPriority: 5, 272 | progressedChild: [Object], 273 | progressedFirstDeletion: null, 274 | progressedLastDeletion: null, 275 | alternate: null, 276 | _debugID: 3, 277 | _debugSource: [Object], 278 | _debugOwner: null }, 279 | sibling: null, 280 | index: 0, 281 | ref: null, 282 | pendingProps: null, 283 | memoizedProps: null, 284 | updateQueue: null, 285 | callbackList: null, 286 | memoizedState: { element: [Object] }, 287 | effectTag: 0, 288 | nextEffect: null, 289 | firstEffect: 290 | { tag: 1, 291 | key: null, 292 | type: [Function: Text], 293 | stateNode: null, 294 | return: [Circular], 295 | child: [Object], 296 | sibling: null, 297 | index: 0, 298 | ref: null, 299 | pendingProps: null, 300 | memoizedProps: [Object], 301 | updateQueue: null, 302 | callbackList: null, 303 | memoizedState: null, 304 | effectTag: 0, 305 | nextEffect: null, 306 | firstEffect: null, 307 | lastEffect: null, 308 | pendingWorkPriority: 0, 309 | progressedPriority: 5, 310 | progressedChild: [Object], 311 | progressedFirstDeletion: null, 312 | progressedLastDeletion: null, 313 | alternate: null, 314 | _debugID: 3, 315 | _debugSource: [Object], 316 | _debugOwner: null }, 317 | lastEffect: 318 | { tag: 1, 319 | key: null, 320 | type: [Function: Text], 321 | stateNode: null, 322 | return: [Circular], 323 | child: [Object], 324 | sibling: null, 325 | index: 0, 326 | ref: null, 327 | pendingProps: null, 328 | memoizedProps: [Object], 329 | updateQueue: null, 330 | callbackList: null, 331 | memoizedState: null, 332 | effectTag: 0, 333 | nextEffect: null, 334 | firstEffect: null, 335 | lastEffect: null, 336 | pendingWorkPriority: 0, 337 | progressedPriority: 5, 338 | progressedChild: [Object], 339 | progressedFirstDeletion: null, 340 | progressedLastDeletion: null, 341 | alternate: null, 342 | _debugID: 3, 343 | _debugSource: [Object], 344 | _debugOwner: null }, 345 | pendingWorkPriority: 0, 346 | progressedPriority: 5, 347 | progressedChild: 348 | { tag: 1, 349 | key: null, 350 | type: [Function: Text], 351 | stateNode: null, 352 | return: [Circular], 353 | child: [Object], 354 | sibling: null, 355 | index: 0, 356 | ref: null, 357 | pendingProps: null, 358 | memoizedProps: [Object], 359 | updateQueue: null, 360 | callbackList: null, 361 | memoizedState: null, 362 | effectTag: 0, 363 | nextEffect: null, 364 | firstEffect: null, 365 | lastEffect: null, 366 | pendingWorkPriority: 0, 367 | progressedPriority: 5, 368 | progressedChild: [Object], 369 | progressedFirstDeletion: null, 370 | progressedLastDeletion: null, 371 | alternate: null, 372 | _debugID: 3, 373 | _debugSource: [Object], 374 | _debugOwner: null }, 375 | progressedFirstDeletion: null, 376 | progressedLastDeletion: null, 377 | alternate: [Circular], 378 | _debugID: 1, 379 | _debugSource: null, 380 | _debugOwner: null }, 381 | _debugID: 1, 382 | _debugSource: null, 383 | _debugOwner: null 384 | } 385 | ``` 386 | --------------------------------------------------------------------------------