Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Aprendizados de um projeto Elixir OTP
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Amanda
May 26, 2019
Technology
640
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Aprendizados de um projeto Elixir OTP
Elixir Brasil 2019
Amanda
May 26, 2019
More Decks by Amanda
See All by Amanda
Lessons Learned From an Elixir OTP Project
amandasposito
2
99
SOLID - Dependency inversion principle
amandasposito
0
93
Como concorrência funciona em Elixir?
amandasposito
1
240
Programação Funcional & Elixir
amandasposito
3
130
Ecto, você sabe o que é ?
amandasposito
4
250
Novidades no Rails 5
amandasposito
0
100
Rails Engines & RSpec
amandasposito
0
240
Elixir e Phoenix
amandasposito
3
590
Elixir em 5 minutos
amandasposito
1
100
Other Decks in Technology
See All in Technology
水を運ぶ人としてのリーダーシップ
izumii19
4
1.1k
AWS Security Hub CSPMの成功・失敗体験
cmusudakeisuke
0
590
起点・思考・出力で分解する 〜PM業務の自動化設計〜
kazu_kichi_67
2
1.1k
千葉での単身赴任からAWSをやり続け、千葉に戻ってきた話
yama3133
1
120
フルAIで個人開発して学んだあれこれ / yuruai vol.1
isaoshimizu
0
150
自作お家AIエージェントスタックチャンFWで困っている所紹介
74th
0
130
データレイクの「見えない問題」を可視化する
sansantech
PRO
1
230
4人目のSREはAgent
tanimuyk
0
280
#エンジニアBooks 30分でわかる 「技術記事を書く技術」 / engineer-books 2026-06-30
jnchito
1
130
Hatena Engineer Seminar 37 jj1uzh
jj1uzh
0
160
はてなのサービス基盤を支える Kubernetes《足腰》
masayoshimaezawa
0
180
時期が悪い!それでもRaspberry Piを買って遊んで活用するには / 20260627-osc26do-rpi-jikigawarui
akkiesoft
1
900
Featured
See All Featured
エンジニアに許された特別な時間の終わり
watany
107
250k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
450
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
280
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
450
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
160
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
310
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Bash Introduction
62gerente
615
220k
Designing for Timeless Needs
cassininazir
1
260
How to make the Groovebox
asonas
2
2.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Transcript
Aprendizados de um projeto Elixir/OTP
→ amandasposito.com → speakerdeck.com/amandasposito → linkedin.com/in/amandasposito
careers.plataformatec.com.br
Disclaimer
Como foi começar em um projeto Elixir, vindo de outra
linguagem?
None
None
None
Como utilizar o ferramental da linguagem a seu favor?
None
Lidar com banco de dados se tornou muito mais comum
Preloads
None
SELECT * FROM Courses; SELECT * FROM Users WHERE course_id
= ? SELECT * FROM Users WHERE course_id = ? SELECT * FROM Users WHERE course_id = ?
None
Repo.all from c in Course, preload: [:users]
Ecto tem muitas features interessantes que podem te ajudar no
dia-a-dia
→ Changesets
→ Changesets → Schemas
→ Changesets → Schemas → Ecto.Multi
→ Changesets → Schemas → Ecto.Multi → etc.
Lidando com tabelas gigantescas
Qualquer coisa que fossemos alterar no banco era difícil
None
None
use Mix.Task
defmodule Mix.Tasks.Echo do use Mix.Task @impl Mix.Task def run(_args) do
Mix.shell.info "Hello World" end end
Saber analisar a performance é muito importante
Explain Analyze
EXPLAIN ANALYZE SELECT "courses"."id", "courses"."data" FROM "courses" INNER JOIN "users"
ON ("courses"."user_id" = "users"."id") WHERE "users".account_id = 4500000;
Gather (cost=847239.21..2458486.98 rows=2 width=16) (actual time=35048.574..45161.127 rows=2 loops=1) Workers Planned:
2 Workers Launched: 2 -> Hash Join (cost=846239.21..2457486.78 rows=1 width=16) (actual time=32820.132..45130.374 rows=1 loops=3) Hash Cond: (courses.user_id = users.id) -> Parallel Seq Scan on courses (cost=0.00..1040678.17 rows=45193617 width=16) (actual time=0.044..29710.148 rows=33333333 loops=3) -> Hash (cost=846239.20..846239.20 rows=1 width=8) (actual time=8318.392..8318.392 rows=1 loops=3) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on users (cost=0.00..846239.20 rows=1 width=8) (actual time=819.773..8318.380 rows=1 loops=3) Filter: (account_id = 4500000) Rows Removed by Filter: 49999999 Planning time: 0.421 ms Execution time: 45169.333 ms
None
None
http://blog.plataformatec.com.br/2019/02/migrations-in-databases-with-large-amount-of-data/
Tabelas ETS
"These provide the ability to store very large quantities of
data in an Erlang runtime system, and to have constant access time to the data." — Erlang Documentation
def hello do opts = [ :set, :named_table, :public, read_concurrency:
true ] table_name = :elixir_brasil :ets.new(table_name, opts) for n <- 1..100 do :ets.insert(table_name, {n, "Key #{n}"}) end end
None
Nesse momento não tinhamos muita visão da quantidade de dados
Velocidade x Quantidade de itens
A estimativa estava em 76GB de consumo de memória por
máquina
None
Tabelas ETS não possuem muitas opções de otimização como o
Redis
None
São como se fossem um Hash direto na memória
Consomem a memória disponível da aplicação
None
https://moz.com/devblog/moz-analytics-db-free
None
Testes
Doctest != Test
None
Sua aplicação está se comunicando com o mundo exterior, e
agora?
None
None
None
None
Como fazer para stubar/mockar uma requisição?
Bypass
None
setup do bypass = Bypass.open {:ok, bypass: bypass} end
test "fetch/1 returns and formats tweets", %{bypass: bypass} do response
= Jason.encode!([%{"text" => "Elixir Brasil 2019"}]) Bypass.expect(bypass, fn conn -> assert "/1.1/search/tweets.json" == conn.request_path assert "GET" == conn.method Plug.Conn.resp(conn, 200, response) end) tweets = TwitterClient.fetch("http://localhost:#{bypass.port}") assert tweets == [%{"text" => "Elixir Brasil 2019"}] end
test "fetch/1 returns and formats tweets", %{bypass: bypass} do response
= Jason.encode!([%{"text" => "Elixir Brasil 2019"}]) Bypass.expect(bypass, fn conn -> assert "/1.1/search/tweets.json" == conn.request_path assert "GET" == conn.method Plug.Conn.resp(conn, 200, response) end) tweets = TwitterClient.fetch("http://localhost:#{bypass.port}") assert tweets == [%{"text" => "Elixir Brasil 2019"}] end
def fetch(url \\ "https://api.twitter.com") do {:ok, response} = HTTPoison.get("#{url}/1.1/search/tweets.json") Jason.decode!(response.body)
end
Quando usar bypass?
Código que precisa realizar requests HTTP
None
Mox
None
None
test "messages/0 lists all messages from the timeline" do TwitterMock
|> expect(:fetch, fn -> [%{"text" => "Olá mundo"}] end) assert Timeline.messages() == {:ok, 1} end https://github.com/amandasposito/mox_example
http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/
GenServer
Como testar processos?
Testar Callback de GenServer não é uma boa prática
None
GenServer.cast
GenServer.call
https://devonestes.herokuapp.com/unit-tests-in-elixir-part-2
Quais os problemas mais comuns encontrados?
→ Tudo que eu aprendi em OOP, vou jogar fora
em funcional? → Como eu organizo meu código? → Todos os problemas que eu tinha em OOP, somem em funcional? → E esse tal de Context? Comé qui usa?
A probabilidade do código ficar complexo diminui
Mas os problemas ainda existem
Muitos dos problemas que vemos em OOP reconhecemos em FP
→ Funções muito grandes
→ Funções muito grandes → Funções difíceis de testar
→ Funções muito grandes → Funções difíceis de testar →
Mudanças simples precisam ser feitas em vários lugares
→ Funções muito grandes → Funções difíceis de testar →
Mudanças simples precisam ser feitas em vários lugares → Feature Envy
→ Funções muito grandes → Funções difíceis de testar →
Mudanças simples precisam ser feitas em vários lugares → Feature Envy → Contextos com muitas linhas
→ Funções muito grandes → Funções difíceis de testar →
Mudanças simples precisam ser feitas em vários lugares → Feature Envy → Contextos com muitas linhas → Acoplamento
→ Funções muito grandes → Funções difíceis de testar →
Mudanças simples precisam ser feitas em vários lugares → Feature Envy → Contextos com muitas linhas → Acoplamento
https://youtu.be/eldYot7uxUc
None
Contexts
A idéia é definir limites entre diferentes módulos da aplicação
Com o passar do tempo e a necessidade de interação
com vários schemas
Os contextos podem ficar maiores do que deveriam
Preste atenção para não manter código ortogonal ao contexto, no
contexto
Mantenha queries próximas de seu schema
A exceção são queries que lidam com mais de um
schema
http://devonestes.herokuapp.com/a-proposal-for-context-rules
None
Umbrella Projects
Dentro de um Umbrella app os apps deveriam acessar arquivos
uns dos outros?
É uma maneira de organizar seu código
None
None