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
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
100
SOLID - Dependency inversion principle
amandasposito
0
94
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
600
Elixir em 5 minutos
amandasposito
1
100
Other Decks in Technology
See All in Technology
侵入は突然に 〜 IoTマルウェアと悪用される家庭の機器 ~ / When Intrusion Strikes: IoT Malware and the Abuse of Home Devices
nttcom
0
1.6k
JavaScript 研修 (2026)
recruitengineers
PRO
2
530
Service Connect 上のサービスに ECS Service の外側から到達できなかった話
ota1022
1
230
AIコーディングの次。コードレビューと理解負荷を解消して組織の開発生産性を高める
moongift
PRO
2
2.5k
認知負荷をGemini で溶かす — GKE 基盤「Orbit」における AI エージェントの実践
sansantech
PRO
1
290
モバイルアプリ開発概論2026
recruitengineers
PRO
5
570
名刺メーカーDevグループ 紹介資料
sansan33
PRO
0
1.2k
Bill One 開発エンジニア 紹介資料
sansan33
PRO
7
19k
[しろおび夏祭り2026] チャットするAIから、作業するAIへ - 使われ方の変化と、その裏側で起きていること
kk0n
0
1.7k
Data Hubグループ 紹介資料
sansan33
PRO
0
3.2k
Flutterをカメラで動かしたかった話
sony
1
140
私がブラウザを自作したくなった理由
supurazako
1
210
Featured
See All Featured
Raft: Consensus for Rubyists
vanstee
141
7.6k
The Curious Case for Waylosing
cassininazir
1
450
Automating Front-end Workflow
addyosmani
1369
210k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
The Cost Of JavaScript in 2023
addyosmani
55
10k
BBQ
matthewcrist
89
10k
Rails Girls Zürich Keynote
gr2m
96
14k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
380
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
470
The browser strikes back
jonoalderson
0
1.5k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
520
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