Skip to content

Latest commit

 

History

History
77 lines (54 loc) · 4.39 KB

File metadata and controls

77 lines (54 loc) · 4.39 KB

MANDATORY: Use td for Task Management

Run td usage --new-session at conversation start (or after /clear). This tells you what to work on next.

Sessions are automatic (based on terminal/agent context). Optional:

  • td session "name" to label the current session
  • td session --new to force a new session in the same context

Use td usage -q after first read.

Project guidelines

  • Use mix precommit alias when you are done with all changes and fix any pending issues
  • Use the already included and available :req (Req) library for HTTP requests, avoid :httpoison, :tesla, and :httpc. Req is included by default and is the preferred HTTP client for Phoenix apps

Elixir guidelines

  • Elixir lists do not support index based access via the access syntax

    Never do this (invalid):

    i = 0
    mylist = ["blue", "green"]
    mylist[i]
    

    Instead, always use Enum.at, pattern matching, or List for index based list access, ie:

    i = 0
    mylist = ["blue", "green"]
    Enum.at(mylist, i)
    
  • Elixir variables are immutable, but can be rebound, so for block expressions like if, case, cond, etc you must bind the result of the expression to a variable if you want to use it and you CANNOT rebind the result inside the expression, ie:

    # INVALID: we are rebinding inside the `if` and the result never gets assigned
    if connected?(socket) do
      socket = assign(socket, :val, val)
    end
    
    # VALID: we rebind the result of the `if` to a new variable
    socket =
      if connected?(socket) do
        assign(socket, :val, val)
      end
    
  • Never nest multiple modules in the same file as it can cause cyclic dependencies and compilation errors

  • Never use map access syntax (changeset[:field]) on structs as they do not implement the Access behaviour by default. For regular structs, you must access the fields directly, such as my_struct.field or use higher level APIs that are available on the struct if they exist, Ecto.Changeset.get_field/2 for changesets

  • Elixir's standard library has everything necessary for date and time manipulation. Familiarize yourself with the common Time, Date, DateTime, and Calendar interfaces by accessing their documentation as necessary. Never install additional dependencies unless asked or for date/time parsing (which you can use the date_time_parser package)

  • Don't use String.to_atom/1 on user input (memory leak risk)

  • Predicate function names should not start with is_ and should end in a question mark. Names like is_thing should be reserved for guards

  • Elixir's builtin OTP primitives like DynamicSupervisor and Registry, require names in the child spec, such as {DynamicSupervisor, name: MyApp.MyDynamicSup}, then you can use DynamicSupervisor.start_child(MyApp.MyDynamicSup, child_spec)

  • Use Task.async_stream(collection, callback, options) for concurrent enumeration with back-pressure. The majority of times you will want to pass timeout: :infinity as option

Mix guidelines

  • Read the docs and options before using tasks (by using mix help task_name)
  • To debug test failures, run tests in a specific file with mix test test/my_test.exs or run all previously failed tests with mix test --failed
  • mix deps.clean --all is almost never needed. Avoid using it unless you have good reason

Test guidelines

  • Always use start_supervised!/1 to start processes in tests as it guarantees cleanup between tests
  • Avoid Process.sleep/1 and Process.alive?/1 in tests
    • Instead of sleeping to wait for a process to finish, always use Process.monitor/1 and assert on the DOWN message:

      ref = Process.monitor(pid) assert_receive {:DOWN, ^ref, :process, ^pid, :normal}

    • Instead of sleeping to synchronize before the next call, always use _ = :sys.get_state/1 to ensure the process has handled prior messages

Coding Guidelines

  • Add all secrets to runtime.exs file and use System.get_env/1 to access them
  • If you are asked to fix a bug YOU MUST add a test that reproduces the bug and then fix the bug
  • Whenever you think your finished making a change the user requested, run a mix check to check for compilation errors, test regressions, and code quality
  • When adding a large feature or change, add a tests as well. If your making small little changes you can use your best judgement as to whether a test is needed or not.