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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
110
SOLID - Dependency inversion principle
amandasposito
0
97
Como concorrência funciona em Elixir?
amandasposito
1
240
Programação Funcional & Elixir
amandasposito
3
140
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
110
Other Decks in Technology
See All in Technology
20260804_Q4AzureUpdateBite_FabricDataAgentの精度を高める設計.pdf
matayuuu
1
140
モノリス Rails でも日中に rails db:migrate を走らせたい! / Daytime rails db:migrate on Monolithic Rails!
euglena1215
4
630
LLM Internals: 언어 모델의 계보와 알고리즘 진화 (2023~2026)
inureyes
PRO
0
560
Head First モブプログラミング / Head First Mobprogramming
takaking22
10
12k
Agent 時代の Kaggle 展望 / kaggle-in-the-agentic-era
upura
1
800
Service Connect 上のサービスに ECS Service の外側から到達できなかった話
ota1022
1
270
Sets in Go
ramalho
1
980
まちスペース®とデジタルツインと「まちづくり」
hiro_ogi
0
130
What's new in Go 1.27?
ciarana
0
210
ブラウザ研修 2026
recruitengineers
PRO
6
1.1k
DatadogのBits Chatが開発組織にもたらしたもの / What Bits Chat Has Brought Us
sms_tech
1
280
20分でわかるセキュアAPI
nwiizo
2
300
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
190
YesSQL, Process and Tooling at Scale
rocio
174
15k
Balancing Empowerment & Direction
lara
6
1.2k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
210
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
Product Roadmaps are Hard
iamctodd
55
12k
Building Applications with DynamoDB
mza
96
7.2k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
420
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
420
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
The browser strikes back
jonoalderson
0
1.5k
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