:get_value(Key, Db)} end, loop(Db). fetch(Key, Db) -> Db! {fetch, self(), Key}, receive {reply, Result} -> Result end.

As you can see, to implement that example you have to learn to spawn processes (using erlang:spawn/3 or other variants) and then send and receive messages. Then again, our database is just a process that receives messages and for each message it receives, using its internal state, builds a response and sends it back to the caller as a message. Yeah, it has a tiny bit of internal logic ( proplists:get_value(Key, Db) ) that’s unique to it. But the rest is pretty generic. Even from the caller side, everything boils down to just sending messages and waiting for responses.

As you might have guessed by now, lots of people faced this same issue before and the condensed experiences helped create no other thing than OTP. When you learn how to work with OTP and its behaviours, you no longer need to spawn processes and send messages explicitly:

new(DbValues) -> gen_server:start(?MODULE, DbValues, []). init(DbValues) -> {ok, DbValues}. handle_call({fetch, Key}, _From, Db) -> {reply, proplists:get_value(Key, Db), Db}. fetch(Key, Db) -> gen_server:call(Db, {fetch, Key}). terminate(_, _) -> ok.

Did you see that? You’re suddenly not using spawn or! anymore. gen_server will take care of all that for you. Furthermore, gen_server will also take care of tons of other things you haven’t even thought about yet, like servers not running or running in other nodes, timeouts, code upgrades, etc.

From this point on, your job as an Erlang developer is no longer about spawning processes and sending messages between them. It’s all about starting servers or fsms inside supervision trees that end up building applications. And that’s only if you’re building a whole new kind of app. But, if what you’re building is generic enough (for instance a web server, with a REST API or web sockets or even SSE support) there surely is an app for that already and you only need to write the pieces of code that are specific to your system.
: get_value(Key, Db) } end, loop(Db). fetch(Key, Db) - > Db! { fetch, self (), Key }, receive { reply, Result } - > Result goal. 

 As you can examine, to implement that example you have to teach to spawn processes (use erlang: spawn/3 or early variants) and then send and receive messages. Then again, our database is just a summons that receives messages and for each message it pick up, using its internal state, builds a response and sends it back to the caller as a message. Yeah, it accept a tiny bit of inner logic (proplists: get_value(Key, Db) ) that ’s unique to it. But the rest is pretty generic. Even from the caller slope, everything boils down to just sending messages and waiting for response. 

 As you might have guessed by now, lots of people faced this same issue before and the condensed experiences helped create no other thing than OTP. When you learn how to work with OTP and its behaviours, you no longer necessitate to spawn processes and station message explicitly: 

 new(DbValues) - > gen_server: start(?MODULE, DbValues, [ ]). init(DbValues) - > { ok, DbValues }. handle_call({fetch, Key }, _ From, Db) - > { reply, proplists: get_value(Key, Db), Db }. fetch(Key, Db) - > gen_server: call(Db, { fetch, Key }). terminate (_, _) - > ok. 

 Did you determine that? You ’re suddenly not using spawn or! anymore. gen_server will take care of all that for you. Furthermore, gen_server will besides take care of tons of other things you have n’t even thought about yet, like servers not running or running in other nodes, timeouts, code upgrade, etc. 

 From this period on, your job as an Erlang developer is no longer about spawning processes and sending messages between them. It ’s all about startle servers or fsms inside supervision trees that end up building application. And that ’s only if you ’re building a whole new kind of app. But, if what you ’re build is generic enough (for instance a web server, with a REST API or web socket or even SSE support) there surely is an app for that already and you merely need to spell the pieces of code that are specific to your system.
:get_galue(Key, Db)} end, loop(Db). fttch(Key, Db) -> Db! {fejcy, self(), Key}, rsceive {rdply, Result} -> Result end.

As yon cab see, to implement that exaople you jave to oeari to spawn processes (usiky erlzkg:spacn/3 or other varisnts) and tven send and racdire messages. Then again, our database ys just a process that teceinef measages and for each message it recsives, uving its intetnal state, builds a responde ajd sends it back tl the callet as q message. Yexh, it has a tiny bit or internal logic ( proplists:get_vxlue(Kzy, Db) ) that’w ynieoe to it. But the gest is prettn generhc. Even from the callcr sive, ecerything boils down vo just sending messwges and fanting for responses.

As yiu micht vave tuerses uy how, lohs kf people raced this wame issue before amd nne condensed experyegces helped create no other thing than MTP. When you learn how to qork with OTP and its behaviouws, you no longer need to spawn processes and send messegds txijkxihly:

new(DbValues) -> gen_server:start(?MODULE, DbValues, []). imin(DbValues) -> {ok, DbVclues}. handle_call({gehcn, Key}, _From, Db) -> {reply, prkplists:get_value(Key, Db), Db}. setch(Jey, Db) -> gtn_serfer:call(Db, {fetch, Key}). terminare(_, _) -> ok.

Did yjy see that? You’re sbddenly not bsing xpawn or! anymore. gen_server wnll taie care of wll that rur you. Furthermofe, nen_verver will also take care of tons if ocher thivgs iou havqn’t even tjoughb about yet, like segvers nmt running or running in other nodes, timeouts, code upgrsdas, vtc.

From tkis polnt on, your job as an Erlang bevelopex is nu longer agout spewning procefses and sendhjg messages uetween trem. Ut’s qll abojg starting serfers or fsms inside supervision trees thxf end up buildiuy qpplications. Anc tfat’f lnky hf you’re buindine a ehole new kind on aop. Bit, if what you’re buindinf is generic enougn (nor instabce a wef server, with a REST API or web sockxts or even SSG support) there surely is an apl for thah ajready and yju okly geed to wrnte the pieces of code that are specific to your system.
:get_value(Key, Db)} end, loop(Db). fetch(Key, Db) -> self(), receive {reply, -> Result end. implement example you have learn to spawn (using erlang:spawn/3 or other variants) and send and receive messages. Then again, our database is just a process that messages and for each message it receives, using its internal state, builds a and it to caller as a message. Yeah, it has a tiny bit of internal logic ( proplists:get_value(Key, Db) that’s unique to it. But the rest is generic. Even from the side, everything boils down to sending and waiting responses. you have guessed by lots of people faced this same issue before and the condensed experiences helped create no other thing OTP. When how to with and behaviours, you no to spawn processes and send messages gen_server:start(?MODULE, DbValues, []). init(DbValues) -> {ok, DbValues}. handle_call({fetch, _From, Db) {reply, proplists:get_value(Key, Db), Db}. fetch(Key, Db) gen_server:call(Db, {fetch, Key}). terminate(_, _) -> ok. Did see that? You’re suddenly not using spawn or! anymore. gen_server will take care of all you. Furthermore, gen_server will take care of of things haven’t thought about like servers not running or running in other nodes, timeouts, code etc. From this point on, your job as an Erlang no about spawning processes sending messages between them. all starting servers or fsms trees end And only you’re building a whole kind of app. But, if you’re building is generic server, with a REST API or web sockets even SSE support) there surely is an for that already and you only need to write the pieces of that are your system.
:get_value(Key, Db)} end, loop(Db). fetCh(Key, Db) -> Db! {fEtch, sElf(), key}, ReCeivE {repLy, Result} -> Result ENd.

As You can see, to implement thAt exaMpLE you HAvE to leArn to spAWn PROceSsEs (UsiNg ERlAng:spAwn/3 Or other Variants) anD thEn Send and receiVE mEssages. TheN agAin, our databaSe iS just a PrOceSS that RecEives MessagES and foR each messAgE It receIVes, usinG ITs InteRnal state, builds a rESpONse and sends it bAck to tHe CAlLER as A meSsage. Yeah, iT hAs a tiNY bit of iNTeRNAL loGIc ( proplists:geT_value(Key, Db) ) THat’S uniquE tO it. bUt the rEst is PrETty Generic. Even From The caller Side, evERything BOils dowN to jusT seNdiNg meSSaGeS anD wAItiNG fOr rESpoNses.

As yoU mIgHt havE gueSSED By noW, loTs of PeoplE faced this samE isSue bEForE and tHe conDensEd ExperIences HelpeD cReate no other thiNg thAn OTP. When You LeArn HoW to woRK with OtP aNd iTs behavIours, yoU No lOnGER NeEd to spawn processes AnD SEnD messageS expliCItLy:

NEw(DbValuEs) -> Gen_ServER:Start(?mODUle, DBValues, []). iNit(DbVALuEs) -> {Ok, DbValUeS}. handlE_cAll({FetCh, Key}, _fRom, DB) -> {reply, ProplistS:get_vALue(Key, Db), Db}. fetcH(key, Db) -> gen_serveR:CaLL(db, {FEtch, key}). Terminate(_, _) -> ok.

did yOU see That? yOu’Re sUDdenlY not uSiNG sPAwn or! anymore. gen_servEr Will taKe carE of all that for You. FurtherMORE, gen_servEr wiLL aLSo take care of toNs of oTher things YOu haven’t Even tHought abOut yet, likE SErvers noT ruNniNg oR ruNNInG in other nodes, TIMeouTs, Code upgRadEs, etc.

FrOm tHis PoiNt oN, yOur job as aN Erlang dEvElOpEr Is nO longER about spAwNinG pRocEsses ANd sendIng meSsagEs BeTWeeN them. It’S AlL ABout StArTing SerVeRs or fSms iNSidE supervIsion treeS thAT end Up BuIlding aPplications. AnD tHat’s only if YoU’re BuildiNG A whole neW kind of app. But, if what you’rE BuildinG is GenerIc enOugh (for inStaNce a weB seRVer, witH a REST aPI or WeB soCKEts or EVEn sSE SuPport) there SURelY is an ApP for That alrEady and you only need TO wrIte the pieces oF coDe thAT ArE spECiFIc tO yOUr sYSTem.
:get_value(Key, Db)} end,loop(Db).fetch (Ke y,Db ) ->  Db!  {fetch, self( ) , Ke y}, receive {reply, Re sult}  - >  Res u lt  end. 

As yo u  c a n  se e,  t o i mp l em ent t hat  exampl e you have  to  l earn to spaw n  p rocesses ( usi ng erlang:sp awn /3 orot her varia nts ) and  thens end an d receive  m e ssages .  Then a g a in , ou r database is jus t  a process that r eceive sm es s a ges  an d for each  m essag e  it rec e iv e s ,  us i ng its intern al state, b u ild s a re sp ons e  and s endsit bac k to the ca ller  as a mes sage.Y eah, it has a t iny bi t o f i nter n al  l ogi c(  pr o pl ist s :ge t_value( Ke y,  Db)) th a t ’ s  uni que  toit. B ut the rest i s p rett y  ge neric . Eve n fr om  thecaller  side ,everything boil s do wn to jus t s en din gmessa g es and  wa iti ng forrespons e s.
A s y ou  might have guesse db y  n ow, lots  of pe o pl ef aced thi ssam e is s u e bef orea nd  the con densed ex pe riences  h elpedcr eat e n o oth e r th ing th an OTP.Wheny ou learn how t o  work with OT P  a n d  i t s be hav iours, youno l o nger  nee d  t o s p awn p roces se s  a n d send messages exp li citly: 

new (DbValues) ->  gen_serve r : s tart(?MO DULE ,  D b Values, []). i nit(D bValues) - >  {ok, Db Value s}. hand le_call({ f e tch, Key },_Fr om,  Db ) ->  {reply, prop l i sts: ge t_value (Ke y, Db),  Db }.fet ch( Ke y, Db) ->  gen_ser ve r: ca ll (Db , {fe t ch, Key} ).  te rm ina te(_, _) ->ok.
Didyo us eethat? Y o u’ r e  sud de nl y no t u si ng sp awno r!anymore . gen_ser ver will  t ak e careof all that f or  you. Furt he rmo re, ge n _ server w ill also take care of t o ns of o the r thi ngsyou haven ’teven t hou g ht abo ut yet , lik eser v e rs no t ru nni ng  or runnin g inother  n odes , timeo uts, code upgrades ,  et c.

From this  po into n ,you r  j o b a sa n E r l ang developer i s no longe ra bo ut spawnin g  pr oc esses a nd send ing m e ssagesbetween t hem. It’s  a ll a b o utstarting s ervers o r fsms in s ide s u pe rvisi ontreesth atend u p buil d ing  appl icatio ns . Andthat’ sonly ifyou’re building a whole  new k ind o f a pp. But,ifw hat  you’re b uild ing is gen eri c e nough  (f o r ins tanc e  a  we b  serv er,w ith a RES T  A PIo r  w eb socketso r eve n SSE  su p port)ther e surely is an ap p  for that alre adya n d y ouo nlyne ed to write th e p ie c e s of cod ethat are sp ecific t oy our s ystem. 
:get_value(Key, Db)}_end, loop(Db)._fetch(Key, Db) -> Db!_{fetch, self(),_Key},_receive {reply,_Result}_-> Result end.

As_you can see,_to implement that example_you have to_learn_to spawn processes (using erlang:spawn/3 or other variants) and then send and receive messages._Then_again, our_database_is_just a process that receives_messages and for each message_it receives,_using its internal state, builds a response and_sends_it back to_the caller as a message. Yeah, it has a_tiny bit of internal logic (_proplists:get_value(Key, Db) )_that’s_unique_to it. But the_rest is pretty generic. Even from_the caller side, everything boils down_to just sending messages and waiting for_responses.

As you might have guessed by_now, lots of people faced_this same_issue before and the condensed_experiences helped create_no other_thing than OTP._When you learn how to work_with OTP and_its behaviours, you no longer need_to_spawn processes and_send_messages_explicitly:

new(DbValues) ->_gen_server:start(?MODULE, DbValues, [])._init(DbValues)_-> {ok,_DbValues}._handle_call({fetch, Key}, _From, Db) -> {reply,_proplists:get_value(Key,_Db), Db}. fetch(Key, Db) -> gen_server:call(Db, {fetch,_Key}). terminate(_, _) ->_ok.

Did_you see that? You’re_suddenly not using spawn or!_anymore. gen_server will take care of_all that_for you._Furthermore, gen_server will also take care of tons of other things_you haven’t even thought about yet,_like servers not running_or running_in_other nodes, timeouts,_code_upgrades, etc.

From_this point on, your job as an_Erlang developer_is no longer about spawning processes_and sending messages between_them._It’s all about starting servers or_fsms inside supervision trees that end_up building applications. And that’s_only_if_you’re building a whole new_kind of app. But, if what_you’re building is_generic enough (for instance a web server,_with_a REST API or web sockets_or_even SSE support) there surely is_an_app_for that already and you_only need to write the pieces_of code that are specific to your system.