Skip to content

Instantly share code, notes, and snippets.

defmodule Test do
  def test(a, opts \\ []) when is_list(opts) do
    with opts <- opts |> Enum.into(%{foo: :a}) do
      test(a, opts)
    end
  end 
  
  def test(a, opts) do
 IO.inspect(a)
@eprothro
eprothro / communication via narrative.md
Last active January 4, 2023 16:58
Connextra, Gherkin, and Free-form prose for multidisciplinary communication via narrative.

Overview

Getting clients, managers, project managers, designers, and developers on the same page when it comes to feature expectations is hard. Everyone speaking the same language (literally) can go a long way to achieving the same, metaphorically.

There are three common formats that are great for written and verbal communication between stakeholders with different backgrounds, responsibilities, and risk exposures. They are each natural-language, narrative formats (they use plain english) that anyone can understand, but their structrued nature is proven to help clearly communicate behavior, specify intent and synchronize expectations.

Connextra user stories

  • Great for high level feature description
  • Typically bad for detailed behavior description

For a bit of important background, read about using narrative to explicitly define behavior.

Below is an example of documenting a feature's behavior. Feel free to edit this page for clarity, this process and documentation are always evolving. To get started with your own feature once you're familiar with this, use some feature description boilerplate

Comments and descriptions will be in callouts like this, they aren't a part of the sample feature description, but are there to help explain what is being documented, how, and why.


Incoming Calls

The feature name. Features are the highest level of granularity for a product. User Accounts, or Vehicles are features, usually they will be a simple noun, and be one of a handful of things with which users will interact. This also helps clarify explicitly what won't be a part of the product (yet).

<Feature name, noun>

Feature Description

As a User
I want to <do something conceptually simple>
So that <motivation for doing that thing>

It can be difficult to test the different scenarious for a module intended for use by including in another class.

If the class is statically defined in the spec, any later definitions extend, not replace, the first definition - which can cause test issues and breaks isolation between examples.

RSpec.describe SomeModule do
  class SomeIncluder
    include SomeModule
  end
 
defmodule Test do
  def test() do
    raise_ex()
    IO.inspect "unreachable" 
  rescue 
    _ex -> IO.inspect("exception caught")
    :error
  end
 
defmodule VanillaTest do
  
  def foo(%{arg: arg}) do
    IO.inspect("foo/1 with map called: #{arg}")
    foo("success")
  end
  
  def foo(arg) do
    IO.inspect("implementation function foo/1 called: #{arg}")
defmodule MyGraph.Middlewares.ResolutionWithErrorReporting do
@moduledoc """
Middleware to handle application errors and exceptions
"""
require Logger
@behaviour Absinthe.Middleware
@doc """
Call this on existing middleware to replace instances of

Context: batch queries constructed using data from the context

Currently, dataloader/3 helper accepts only statically defined args.

This means we cannot use the dataloader helper to use data from the Absinthe.Resolution to build the batch key.

We can do this directly:

field :is_favorited, non_null(:boolean),

Use a glob route at the bottom of your scopes to catch invalid routes

# config/routes.rb
Rails.application.routes.draw do
  # ... all your scopes and routes
  match "(*any)", to: "application#render_not_found", via: :all
end