Вы находитесь на странице: 1из 193

1 hour dive into

Erlang/OTP

@jvalduvieco

@jordillonch

Problem domain

Lots of users

Lots of users

24x7x365

24x7x365

Lots of critical concurrent


transactions

Lots of critical concurrent


transactions

Hardware or software
breaks

Hardware or software
breaks

Lots of code changes

Lots of code changes

Unscalable
Unmaintainable

code

Unscalable
Unmaintainable

code

Maintenance/Debug
in
production system

Maintenance/Debug
in
production system

Does it sound to you?

The Erlang solution

Simplicity...

Minimize defensive
programming

Typeless variables

Develop by contract

t-shirt function
size
If
 a
 function
 does
 not
 fit

on
 your
 t-shirt
 it
 is
 too
 long!

Single responsibility
principle

No shared state
between entities

High Concurrency

High
High Concurrency
concurrency

Light threads

Light threads

hundreds of thousands of threads in one


machine with a good cpu scheduler

Light threads

hundreds of thousands of threads in one


machine with a good cpu scheduler

Lt
Lt

Lt

Message passing

Lt
Lt

Lt

Message passing
A shared nothing architecture that
communicates through message passing
Lt
Lt

Lt

Message passing
A shared nothing architecture that
communicates through message passing
Lt
Lt

Lt

Process Mailbox

Lt
Lt

Lt

Process Mailbox
Every process has a mailbox with incoming
messages, process take on convenience
Lt
Lt

Lt

No shared state

Lt
S
Lt
S

Lt
S

No shared state
Every process its own internal state stored in
a variable avoiding lock contention
Lt
S
Lt
S

Lt
S

Soft realtime

Soft realtime
You have no strict guarantees on
latency but language is designed
to have low latency

High availability

High
availability
High availability

Supervised processes

Pa

Pb

Supervised processes
processes can be monitored by other
processes, handling its termination

Pa

Pb

Fail early

Pa

Pb
S

Fail early

Fail as soon as possible and let someone


handle bad data, someone will restart you
Pa

Pb
S

Fail early

Fail as soon as possible and let someone


handle bad data, someone will restart you
Pa

Pb2
S

Hot code update

Pb

Pa v1
S
Pc

Hot code update


processes code and data can be replaced
without loosing service

Pb

Pa v1
S
Pc

Hot code update


processes code and data can be replaced
without loosing service

Pb

Pa v2
v1
S
Pc

Distribution

Node

Node

Distribution
Processes run on nodes and can be located
wherever they are
Node

Node

How does it look like?

Show me the code!

Demo 1

Hands on

The shell

Type on your console:


erl

You should see:


Erlang R16B (erts-5.10.1) [source] [64-bit]
[smp:2:2] [async-threads:10] [hipe] [kernelpoll:false] [dtrace]
Eshell V5.10.1
1>

(abort with ^G)

Variables

Variables start
Uppercase

Variables are immutable

Can contain any type

You can do things like...

1> Foo = 1.
1
2> Foo = 2.
** exception error: no match of right hand
side value 2

Foo
 is
 bounded
 to
 1

1> Foo = 1.
1
2> Foo = 2.
** exception error: no match of right hand
side value 2

Foo
 is
 bounded
 to
 1

1> Foo = 1.
1
Foo

=
=

2


?
2> Foo = 2.
** exception error: no match of right hand
side value 2

1> Foo = 1.
1
2> Bar = 2.
2
3> Foo = Bar.
** exception error: no match of right
hand side value 2

This is GREAT!

Now you have your


basic error checking
system implemented

Advanced
types

[List]

[1,2,3,4,5,6]

You can do things like...

Iterate sequentially

1> MyList = [1,2,3,4].


[1,2,3,4]
2> [Head|Tail] = MyList.
[1,2,3,4]
3> Head.
1
4> Tail.
[2,3,4]

1> MyList = [1,2,3,4].


[1,2,3,4]
2> [Head|Tail] = MyList.
[1,2,3,4]
3> Head.
1
4> Tail.
[2,3,4]

1> MyList = [1,2,3,4].


[1,2,3,4]
2> [Head|Tail] = MyList.
[1,2,3,4]
3> Head.
1
4> Tail.
[2,3,4]

Do something to all or
some items on a list
(list comprehensions)

1> MyList = [1, 2, 3, 4].


[1,2,3,4]
2> [X + 2 || X <- MyList, X > 2].
[5,6]

[Strings]

A list

You can do things like...

1> MyString = "Erlang is not Ruby".


"Erlang is not Ruby"

1> MyString = "Erlang is not Ruby".


"Erlang is not Ruby"
2> [Head2|Tail2] = MyString.
"Erlang is not Ruby"
3> Head2.
69 ASC
 =
 E
4> Tail2.
"rlang is not Ruby"

{Tuples}

{1,2,3}

Basic data container

random access

matcheable

You can do things like...

1> Mytuple = {1,2,3,4}.


{1,2,3,4}
2> A = 1.
1
3> B = 2.
2
4> {A,B,C,D} = {1,2,3,4}.
{1,2,3,4}
5> C.
3
6> D.
4

1> Mytuple = {1,2,3,4}.


{1,2,3,4}
2> A = 1.
A
 and
 B
 are
1
3> B = 2. bounded
 variables
2
4> {A,B,C,D} = {1,2,3,4}.
{1,2,3,4}
5> C.
3
6> D.
4

1> Mytuple = {1,2,3,4}.


{1,2,3,4}
2> A = 1.
A
 and
 B
 are
1
3> B = 2. bounded
 variables
2
4> {A,B,C,D} = {1,2,3,4}.
{1,2,3,4}
5> C. pattern
 matching
3
A==1?
6> D.
B==2?
4

1> Mytuple = {1,2,3,4}.


{1,2,3,4}
2> A = 1.
A
 and
 B
 are
1
3> B = 2. bounded
 variables
2
4> {A,B,C,D} = {1,2,3,4}.
{1,2,3,4}
5> C. pattern
 matching
3
A==1?
6> D.
B==2?
4

C
 and
 D
 are

unbounded

variables

functions

functions are types

single exit point

You can do things like...

foo_bar_func(Foo, Bar) ->


Result = Foo + Bar,
Result.

This
 is
 a
 arity
 2
 function

(2
 parameters)
foo_bar_func(Foo, Bar) ->
Result = Foo + Bar,
Result.

This
 is
 a
 arity
 2
 function

(2
 parameters)
foo_bar_func(Foo, Bar) ->
Result = Foo + Bar,
Result.
means
 that
 more

code
 is
 to
 come

This
 is
 a
 arity
 2
 function

(2
 parameters)
foo_bar_func(Foo, Bar) ->
Result = Foo + Bar,
Result.
means
 that
 more

code
 is
 to
 come
means
 the
 function

code
 has
 ended

This
 is
 a
 arity
 2
 function

(2
 parameters)
foo_bar_func(Foo, Bar) ->
Result = Foo + Bar,
Result.
means
 that
 more

code
 is
 to
 come
Single
 exit
 point
Returns
 Result
means
 the
 function

code
 has
 ended

1> FooBar = fun(Foo, Bar) ->


1> Foo + Bar
1> end.
#Fun<erl_eval.12.82930912>
2> Result = FooBar(1, 2).
3

atoms

A constant with name

lowercase

You can do things like...

1> ok.
ok
2> ko.
ko
3> ok =:= ko.
false
4> ok =:= ok.
true

1> MyFuncOK = fun() -> {ok, 33} end.


#Fun<erl_eval.20.82930912>
2> MyFuncFail = fun() -> {error, bad_arg} end.
#Fun<erl_eval.20.82930912>
3> {ok, Result} = MyFuncOK().
{ok,33}
4> {ok, Result2} = MyFuncFail().
** exception error: no match of right hand
side value {error,bad_arg}

atoms
1> MyFuncOK = fun() -> {ok, 33} end.
#Fun<erl_eval.20.82930912>
2> MyFuncFail = fun() -> {error, bad_arg} end.
#Fun<erl_eval.20.82930912>
3> {ok, Result} = MyFuncOK().
{ok,33}
4> {ok, Result2} = MyFuncFail().
** exception error: no match of right hand
side value {error,bad_arg}

atoms
1> MyFuncOK = fun() -> {ok, 33} end.
#Fun<erl_eval.20.82930912>
2> MyFuncFail = fun() -> {error, bad_arg} end.
#Fun<erl_eval.20.82930912>

3> {ok, Result} = MyFuncOK().


error
{ok,33}
checking
4> {ok, Result2} = MyFuncFail().
** exception error: no match of right hand
side value {error,bad_arg}

atoms
1> MyFuncOK = fun() -> {ok, 33} end.
#Fun<erl_eval.20.82930912>
2> MyFuncFail = fun() -> {error, bad_arg} end.
#Fun<erl_eval.20.82930912>

3> {ok, Result} = MyFuncOK().


error
{ok,33}
checking
4> {ok, Result2} = MyFuncFail().
** exception error: no match of right hand
side value {error,bad_arg}

do
 they
 match?

modules

basic name spacing

public/private functions

You can do things like...

On your ${EDITOR} create cool_func.erl

-module(cool_func).
-export([foo_bar_func/2]).
foo_bar_func (Foo, Bar) ->
Result = Foo + Bar,
{ok, Result}.

On erlang shell type:


1> c("cool_module").
{ok,cool_module}
2> {ok, Result3} = cool_module:sum(33, 44).
{ok,77}
3> Result3.
77

Too easy?

Lets add some pattern


matching on parameters!

area({square, Side}) ->


{ok,Side * Side};
area({circle, Radius}) ->
% almost :-)
{ok, 3 * Radius * Radius};
area({triangle, A, B, C}) ->
S = (A + B + C)/2,
{ok, math:sqrt(S*(S-A)*(S-B)*(S-C))};
area(Other) ->
{error, invalid_object}.

area({square, Side}) ->


{ok,Side * Side};
means
 that
 there
 is

area({circle, Radius}) ->
another
 matching

posibility
% almost :-)
{ok, 3 * Radius * Radius};
area({triangle, A, B, C}) ->
S = (A + B + C)/2,
{ok, math:sqrt(S*(S-A)*(S-B)*(S-C))};
area(Other) ->
{error, invalid_object}.

area({square, Side}) ->


{ok,Side * Side};
means
 that
 there
 is

area({circle, Radius}) ->
another
 matching

posibility
% almost :-)
{ok, 3 * Radius * Radius};
area({triangle, A, B, C}) ->
S = (A + B + C)/2,
{ok, math:sqrt(S*(S-A)*(S-B)*(S-C))};
area(Other) ->
{error, invalid_object}.

mymodule:area({square, 10}).
mymodule:area({circle, 10}).
mymodule:area({triangle, 2, 2, 3.5}).

Want more?
Lets add some recursion!

Want more?
Lets add some recursion!
Erlang does not use loops

factorial(0) -> 1;
factorial(N) -> N * factorial(N-1).

OTP

Oh, This is Perfect!

OTP is a set of rock solid


architecture patterns,
practices and tools

Improves the design,


fault tolerance and
deployment of your app

Erlang is just a language,


OTP makes it great for
the real world

Basic architecture
patterns

Supervisor
S

Supervisor
S

Supervisor spawns processes


and handles its death

gen_server
P

gs

gen_server
P

gs

Generic single threaded server

gen_fsm
P

gf{S}

gen_fsm
P

gf{S}

Generic Finite State Machine

gen_event
P
P

P
em
P

P
P

gen_event
P
P

P
em
P

P
P

Event handler, you can


subscribe to events

More on OTP...
File hierarchy
Applications
Releases
Basic abstraction libraries (logging,
system...)

Lets see a gen_server


in action!

Introducing
Simple Key Value Store

A server that is able to


store {Key,
Value} and retrieve
them by Key

Demo II

skvs diagram
S

gs
ets

skvs diagram
S

gs
ets

Starting skvs
Go to skvs source directory
Compile
./rebar compile

Start the Erlang node


erl -pa ebin

Start the app


application:start(skvs).

Some commands
Set a value
skvs_server:set(Key,Value).
skvs_server:set(Key2,Value2).

Get a value
skvs_server:get(Key2).

Code on client: skvs_server.erl


start_link() ->
gen_server:start_link({local, skvs},
skvs_server, [], []).
get(Key) ->
gen_server:call(skvs, {get, Key}).
set(Key,Value) ->
gen_server:call(skvs, {set, Key, Value}).
set_fire_and_forget(Key,Value) ->
gen_server:cast(skvs, {set, Key, Value}).

Code on client: skvs_server.erl

start
 gen_server

start_link() ->
gen_server:start_link({local, skvs},
skvs_server, [], []).
get(Key) ->
gen_server:call(skvs, {get, Key}).

set(Key,Value) ->
gen_server:call(skvs, {set, Key, Value}).
set_fire_and_forget(Key,Value) ->
gen_server:cast(skvs, {set, Key, Value}).

Code on client: skvs_server.erl

start
 gen_server

start_link() ->
gen_server:start_link({local, skvs},
skvs_server, [], []).
get(Key) ->
gen_server:call(skvs, {get, Key}).

sync
 call
 to
 server
(waits
 for
 reply)

set(Key,Value) ->
gen_server:call(skvs, {set, Key, Value}).
set_fire_and_forget(Key,Value) ->
gen_server:cast(skvs, {set, Key, Value}).

Code on client: skvs_server.erl

start
 gen_server

start_link() ->
gen_server:start_link({local, skvs},
skvs_server, [], []).
get(Key) ->
gen_server:call(skvs, {get, Key}).

sync
 call
 to
 server
(waits
 for
 reply)

set(Key,Value) ->
gen_server:call(skvs, {set, Key, Value}).
set_fire_and_forget(Key,Value) ->
gen_server:cast(skvs, {set, Key, Value}).

async
 call
 to
 server
(fire
 &
 forget)

Callback code: skvs_server.erl


%% Client Callbacks on server
%% Sync calls, expects response
handle_call({set, Key, Value}, _From,State) ->
{reply, set_value(Key,Value), State};
handle_call({get, Key}, _From, State) ->
{reply, get_value(Key), State}.
%% Async calls, do not expect response
handle_cast({set, Key, Value}, State) ->
set_value(Key,Value),
{noreply, State}.

Callback code: skvs_server.erl


%% Client Callbacks on server
%% Sync calls, expects response
handle_call({set, Key, Value}, _From,State) ->
{reply, set_value(Key,Value), State};
handle_call({get, Key}, _From, State) ->
{reply, get_value(Key), State}.
%% Async calls, do not expect response
handle_cast({set, Key, Value}, State) ->
set_value(Key,Value),
{noreply, State}.

return
 value

Callback code: skvs_server.erl


%% Client Callbacks on server
%% Sync calls, expects response
handle_call({set, Key, Value}, _From,State) ->
{reply, set_value(Key,Value), State};
handle_call({get, Key}, _From, State) ->
{reply, get_value(Key), State}.
%% Async calls, do not expect response
handle_cast({set, Key, Value}, State) ->
set_value(Key,Value),
{noreply, State}.

return
 value

Survives
 between

requests

Actual work...: skvs_server.erl


%% Private functions
set_value(Key, Value) ->
% Insert Key, Value into ETS.
% Fail early
{ok,Result}=case ets:insert(data_store,{Key,Value}) of
true ->
{ok, {Key,Value}};
{error, Reason} ->
{error, Reason}
end,
Result.

Actual work...: skvs_server.erl


%% Private functions
set_value(Key, Value) ->
% Insert Key, Value into ETS.
% Fail early
{ok,Result}=case ets:insert(data_store,{Key,Value}) of
true ->
{ok, {Key,Value}};
{error, Reason} ->
{error, Reason}
end,
Result.

ETS
 is
 a
 Key
 value
 store

in
 RAM

Use cases

Gaming Industry

Gaming Industry

Messaging / IM

Messaging / IM

Payments

Payments

Databases

Databases

Others

Others

Some day...

Every highly interactive


website? ;)

Pay

Hello
Ouch!

Every highly interactive


website? ;)

Would you...
NO!

Hey

Buf

Hi

Internet of things

And now what?

Install Erlang/OTP!
https://www.erlang-solutions.com/downloads/download-erlang-otp

Use a great IDE

IntelliJ + Erlang (plugin)


Sublime Text + SublimErl
Emacs

Read some books

RTFM
http://www.erlang.org/doc.html
http://erldocs.com/

Join mailing lists


Official Erlang mailing list
http://erlang.org/mailman/listinfo/erlangquestions

Join Barcelona Erlang user group on google


groups

Find know-how
Check http://www.erlang-factory.com/
videos

Search for Erlang conferences on slideshare


Pray for an http://erlangcamp.com/ near
your city

Read some code

This is the result of 6 months


of fun learning Erlang/OTP

We are looking for awesome


projects

http://es.linkedin.com/in/jvalduvieco
http://es.linkedin.com/in/jllonch

Thank you!
https://github.com/jvalduvieco/betabeers_201303

Thank you!
https://github.com/jvalduvieco/betabeers_201303

we
 hope
 you
 feel

like
 him
 :)
(we
 did)

Erlang, The Movie

http://www.youtube.com/watch?v=uKfKtXYLG78

Images sources
http://diromero.wordpress.com/2011/10/07/home-automation/
http://iffergan.com/
http://technode.com/2012/05/14/internet-of-things-not-just-a-concept-for-fund-raising/
http://modernherstory.wordpress.com/2011/05/18/open-minds-open-hearts/
http://www.i-m.co/eviemouse/problemsolved/
http://strategicsalesmarketingosmg.wordpress.com/2012/06/25/who-are-twitter-users/
http://www.secureworks.com/it_security_services/advantage/soc/
http://labourlist.org/2011/11/my-biggest-worry-about-labour%E2%80%99s-future/broken-chain/
http://prothemedesign.com/how-to/why-you-should-keep-wordpress-and-your-plugins-up-to-date/attachment/matrix-codeupdate/
http://thegapbetweentwoworlds.com/category/career-transition
http://www.wingweb.co.uk/Images/697/KC-10_Extender_SR-71_Blackbird
http://www.tonywoodtraining.com/2010/11/29/motivation-to-exercise-and-eat-right/
http://portalmie.com/blog/6/2011/09/kushimoto-diving-park-tokushima-revista-no-7/
http://www.bcsagroup.com/
http://www.losemyaccent.com/tag/hand/
http://articulo.mercadolibre.com.ar/MLA-450970296-cortaplumas-victorinox-huntsman-15-usos-navaja-origen-suizo-_JM
http://openclipart.org/detail/4112/
http://blog-en.coaching-go.com/2012/02/learn-to-say-no-and-know-how-to-say-yes/ok-2/
http://en.wikipedia.org/wiki/File:We_Can_Do_It!.jpg
http://triniblog.wordpress.com/tag/laberintos/
http://www.catskillsnyrealestate.com/Want-More-Info-Catskill-Real-Estate.php
http://www.thelovelyplanet.net/lush-green-images-planet-earth/
http://www.growthmax.com/how-exactly-does-growthmax-plus-make-you-grow-taller/
http://www.ayurvedalive.in/keep-your-eyes-healthy-beautiful
http://my.mmosite.com/510619/blog/item/lord_of_the_rings_online.html
http://scifistorm.org/2010/03/24/lord-of-the-rings-blu-ray-review/
http://www.123rf.com/photo_15612022_3d-cartoon-bug.html
http://www.airliners.net/photo/1134244/L/
http://www.muypymes.com/2009/12/04/moleskine-mucho-mas-que-una-agenda-personal
http://learnyousomeerlang.com/the-hitchhikers-guide-to-concurrency
http://planetpooks.com/one-more-reason-to-love-hermiones-handbag/

Вам также может понравиться