<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Jun 18, 2014 at 11:02 AM, Loïc Hoguin <span dir="ltr"><<a href="mailto:essen@ninenines.eu" target="_blank">essen@ninenines.eu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Okay I wanted to skip this thread entirely but you mentioned Cowboy and said weird things about it so I'll bite.<div class="">
<br>
<br>
On 06/18/2014 09:39 AM, Aaron J. Seigo wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
comparing with cowboy, the differences are glaring. for instance, in the<br>
"getting started" guide for cowboy:<br>
</blockquote>
><br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
* we live in the microwave popcorn and 10-minutes-is-a-long-video-on-<u></u>youtube<br>
age. yet the first FOUR sections are not about cowboy at all, but talking about<br>
the modern web and how to learn erlang. as someone moderately familiar with<br>
the web, i don't care about this. *just let me get started already!* if i'm<br>
reading the getting started guide for cowboy, i probably don't need to be sold<br>
on either the modern web OR erlang.<br>
</blockquote>
<br></div>
I'm not sure why you call it a "getting started guide" all over your email. It's the user guide. It may have one "getting started" chapter, but its goal is not to get people started, but to be a complete guide. This includes not only practical examples but also theory. Why theory? Well everyone coming to Cowboy isn't a web developer, or even an Erlang developer. Some of my users were happy enough that these chapters were in the guide that they contacted me directly to tell me they liked them.<br>
<br>
If you are a web developer, then why are you reading these chapters? Do you read the documentation for every computer you buy? Do you need to learn how to put the power plug in to charge it? You probably don't need that. But some people do, and that's why we put these "obvious" things in the docs.<div class="">
<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
* being a good, modern developer with the attention span of the average<br>
backyard squirrel i simply skipped straight to the "Getting Started" section.<br>
the FIRST sentence is this:<br>
<br>
"Setting up a working Erlang application is a little more complex than for<br>
most other languages. The reason is that Erlang is designed to build systems<br>
and not just simple applications."<br>
<br>
... aaaaaaaand cowboy just lost me as a user. i don't WANT complex[1], and my<br>
application IS simple. so cowboy is not for me! right?<br>
</blockquote>
<br></div>
Well there's nothing we can do about that. We can't just write one file and run a program on it. That's simply not how Erlang works.</blockquote><div><br></div><div><br></div><div>No no no.</div><div><br></div>
<div>You can - Here is an example of a single file cowboy server that computes</div><div>fib(N) - </div><div><br></div><div><br></div><div>--- start <a href="http://ws3.es">ws3.es</a></div><div><br></div><div><div>#!/usr/bin/env escript</div>
<div>% -*- erlang -*-</div><div>%%! -smp enable -pa ../erl_github_imports/deps/cowboy/ebin -pa ../erl_github_imports/deps/ranch/ebin -pa ../erl_github_imports/deps/cowlib/ebin </div><div><br></div><div>-mode(compile).</div>
<div>-export([init/3, handle/2, terminate/3]).</div><div><br></div><div><br></div><div>main(_) -></div><div> io:format("ws3:starting~n"),</div><div> ok = application:start(crypto),</div><div> ok = application:start(ranch),</div>
<div> ok = application:start(cowlib),</div><div> ok = application:start(cowboy),</div><div> Env = os:getenv("HOME"),</div><div> Dispatch = cowboy_router:compile([{'_', [{'_', ?MODULE, Env}]}]),</div>
<div> </div><div> io:format("Dispatch=~p~n",[Dispatch]),</div><div> io:format("Root=~p~n",[Env]),</div><div> io:format("Info:~p~n",[?MODULE:module_info()]),</div><div> start_http (8124, Dispatch),</div>
<div> forever().</div><div><br></div><div>start_http(Port, Dispatch) -></div><div> NumberOfAcceptors = 1000,</div><div> V = cowboy:start_http(http, NumberOfAcceptors, </div><div><span class="" style="white-space:pre"> </span> [{port, Port}], </div>
<div><span class="" style="white-space:pre"> </span> [{env, [{dispatch, Dispatch}]}</div><div><span class="" style="white-space:pre"> </span> ]),</div><div> io:format("Http Running on Port:~w V=~p~n",[Port, V]).</div>
<div><br></div><div>init({tcp,http}, Req, Env) -></div><div> io:format("Init~n"),</div><div> {ok, Req, {http, Env}}.</div><div><br></div><div>handle(Req, Env) -></div><div> {Path0,Req1} = cowboy_req:path(Req),</div>
<div> Path = binary_to_list(Path0),</div><div> io:format("Path=~p~n",[Path]),</div><div> case Path of</div><div><span class="" style="white-space:pre"> </span>"/fib" -></div><div><span class="" style="white-space:pre"> </span> {Args, Req2} = cowboy_req:qs_vals(Req1),</div>
<div><span class="" style="white-space:pre"> </span> case Args of </div><div><span class="" style="white-space:pre"> </span>[{<<"n">>,BN}] -></div><div><span class="" style="white-space:pre"> </span> N = list_to_integer(binary_to_list(BN)),</div>
<div><span class="" style="white-space:pre"> </span> F = fib(N),</div><div><span class="" style="white-space:pre"> </span> io:format("fib(~p) = ~p~n",[N,F]),</div><div><span class="" style="white-space:pre"> </span> reply_html(integer_to_list(F), Req2, Env);</div>
<div><span class="" style="white-space:pre"> </span>_ -></div><div><span class="" style="white-space:pre"> </span> reply_html(<<"error">>, Req2, Env)</div><div><span class="" style="white-space:pre"> </span> end;</div>
<div><span class="" style="white-space:pre"> </span>_ -></div><div><span class="" style="white-space:pre"> </span> reply_html(<<"error">>, Req1, Env)</div><div> end.</div><div><br></div><div>
<br></div><div>reply_html(Obj, Req, Env) -></div><div> {ok, Req1} = send_page(html, Obj, Req),</div><div> {ok, Req1, Env}.</div><div><br></div><div>terminate(Reason,_Req,State) -></div><div> io:format("Terminated:~p ~p~n",[Reason,State]),</div>
<div> %% ignore why we terminate</div><div> ok.</div><div><br></div><div><br></div><div>fib(0) -> 1;</div><div>fib(1) -> 1;</div><div>fib(N) when is_integer(N), N > 0 -> </div><div> fib(N-1) + fib(N-2).</div>
<div><br></div><div><br></div><div>send_page(Type, Data, Req) -></div><div> cowboy_req:reply(200, [{<<"Content-Type">>,</div><div><span class="" style="white-space:pre"> </span> list_to_binary(mime_type(Type))}],</div>
<div><span class="" style="white-space:pre"> </span> Data, Req).</div><div><br></div><div>mime_type(html) -> "text/html".</div><div><br></div><div>forever() -></div><div> receive</div><div><span class="" style="white-space:pre"> </span>after</div>
<div><span class="" style="white-space:pre"> </span> infinity -></div><div><span class="" style="white-space:pre"> </span>true</div><div><span class="" style="white-space:pre"> </span>end.</div><div><br></div></div>
<div><br></div><div>--- end</div><div><br></div><div>Put this in a file. chmod it to u+x and run it</div><div><br></div><div>Then got to <a href="http://localhost:8124/fib?n=10">http://localhost:8124/fib?n=10</a></div><div>
<br></div><div>And fib(10) will be returned</div><div><br></div><div>Note - I haven't built an application. With a small amount of refactoring this could be</div><div>make just as simple as the node.js examples</div><div>
<br></div><div> The second counter example is rebar? - it's ONE file -</div><div><br></div><div>There are two ways to make single file applications</div><div><br></div><div> 1) make an escript and stick everything in one file. Use the </div>
<div> compile flag if you want the escript to be compiled and not interpreted.</div><div><br></div><div><br></div><div> 2) make a packed escript that packs all the compiled code into a single file</div><div> rebar is a good example of this</div>
<div><br></div><div> The code in</div><div><br></div><div> <a href="https://github.com/basho/rebar/blob/develop/bootstrap">https://github.com/basho/rebar/blob/develop/bootstrap</a><br></div><div><br></div><div>
is a stand-alone script that builds rebar</div><div><br></div><div> Personally I'm rather surprised that there are so few single file programs</div><div>like rebar - they are far easier for the beginner to use and don't break if they</div>
<div>moved to new directories - A single file web server would be very nice to have (hint) ...</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
We have to create an OTP application, compile, </blockquote><div> start the VM with the right paths etc.<br></div><div><br></div><div><div>No you don't - I have large number of programs that are just erlang modules</div>
<div>started with a top level "erl -s ...." command. </div></div><div><br></div><div>Both node and java applications require paths to be correctly set, or for files</div><div>to be in a particular directory structure.</div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">That's not just Cowboy deciding to be more complex than nodejs, that's how Erlang was designed.<br>
</blockquote><div><br></div><div> Erlang was not designed to be complex - the primitives in Erlang (spawn_link, trap_exits, etc.) were designed to be as simple as possible and were intended to be called from library routines.</div>
<div><br></div><div>For example, remote procedure calls are not defined in Erlang, but</div><div>can be built using send and receive.</div><div><br></div><div>If you'd said "OTP was designed for solving more complex problems than node.js"</div>
<div>I'd agree .</div><div><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
And while it's improving (you should have seen things 4 years ago when I started, the getting started in Cowboy is *immensely* simpler than it would have been then), it'll never be as simple as nodejs. Because most of the stuff in the getting started chapter is necessary as I'll explain in a bit.<div class="">
<br></div></blockquote><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="">
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
* the rest of the "getting started" walks me through doing a ton of<br>
boilerplate stuff. it's nice to know how things work, but i'm a busy web dev<br>
(have i mentioned my lack of attention span yet? oh look, a peanut! and it's<br>
an event driven async peanut! yum! *runs off*). everything in that section<br>
ought to be boiled down to "run this one simple command and everything is done<br>
for you. click here to read about the gory details." and doing so should give<br>
me a fully functional application template that i can immediately start. that<br>
one command should probably take a simple config file with things like the app<br>
name and other variable details (such as which erlang apps to include in my<br>
awesome new project, including but also in addition to cowboy). basically, an<br>
npm-for-erlang.<br>
</blockquote>
<br></div>
The next <a href="http://erlang.mk" target="_blank">erlang.mk</a> version will make it a little easier by generating a base project (using templates, as you say). But that will not change the getting started chapter much, as we will still have to explain things. Instead of saying "create" it will say "edit", basically.<br>
<br>
It may sound like a lot for someone with as little attention span as you, but going through these steps saves you an immense amount of time later on. If Erlang beginners start using releases immediately, we win. They will not have to suffer going through hoops like we did to get to that point. They will not have to fiddle with paths, or make start scripts, or deal with complex deployment issues, or anything that we struggled with for years. It *is* a big step, and we probably can't reduce it much more, but it's an incredible time saver.<br>
<br>
But of course impatient people will prefer to waste their time by missing out on it.<br>
<br>
And to be honest if we weren't doing this then we would have to explain how to write a start function, start erl with the -s option and make a start script for frequent use. It wouldn't be simpler, it would just be different, and we would just miss an opportunity to teach beginners "the right way" from the start.<div class="">
<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
oh, and bonus points if there is a file created just for route definitions which<br>
would then be automatically included by the foo_app.erl to be passed to<br>
cowboy_router:compile. having a "well known" place to define routes will<br>
standardize cowboy using applications and allow the starting dev to focus on<br>
what they care about (routes and handlers) while ignoring the details like the<br>
app module. yes, yes, eventually they'll likely want to dig into that as well,<br>
but not at the beginning. (this is an area that cowboy+erlang could be even<br>
better than express+node.js)<br>
</blockquote>
<br></div>
Cowboy isn't a Web framework. There's nothing to standardize. It's a thin HTTP layer implementing the various HTTP specs. That's it. Yes, routing is also part of the spec, as it is a way to map URIs to resources which is well covered by the spec.<br>
<br>
There's tons of Web frameworks built on top of Cowboy if you want standards. Everything in Cowboy is done by calling a function (or Cowboy calling one of your functions). The application module is simply the only place where you can run code at startup, so we have to cover it. Besides I don't see much difference between explaining how to run code in this module vs explaining the structure of a configuration file (it's harder to do the latter really).<div class="">
<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
* i couldn't find the bragging section of the docs. ;) more seriously, the<br>
getting started guide tries to sell me on the modern web and erlang's place in<br>
it, but how about a fun little one-pager that backs up the claims made in the<br>
main README: "Cowboy is a small, fast and modular HTTP server written in<br>
Erlang." and " It is optimized for low latency and low memory usage". show me<br>
the money^Hmeasurements! a simple set of charts showing how many simultaneous<br>
connections can be handled and what kind of latencies app the developers<br>
achieve on regular ol' hardware, along with a LOC-you-need-to-write-for-a-<br>
barebones-app count would help convince people and would be the thing that<br>
would get passed around on stackoverflow, g+, twitter, etc. when justifying /<br>
recommending cowboy.<br>
</blockquote>
<br></div>
Would you believe me if I told you Cowboy is capable of handling millions of concurrent Websocket connections on a middle sized server, with *no impact* on latency? And would you believe me if I told you I do not have the slightest idea what the upper limit for the number of connections Cowboy can actually handle *is*? Because that's the truth.<br>
<br>
This is in large part due to Erlang, Cowboy mostly tries to be careful about memory use, and could do a better job at it.<br>
<br>
But still, how do you even brag about a difference that big with other platforms, and make people actually believe you?<br>
<br>
Besides, if you look at the benchmark of the week, they're still all focused on glorified "hello world" measuring requests per second. Cowboy obviously can't compete there, as these are won by JITs not by the underlaying code. Not to mention these benchmarks are the most misleading and useless kind you can ever write.<span class=""><font color="#888888"><br>
<br>
-- <br>
Loïc Hoguin<br>
<a href="http://ninenines.eu" target="_blank">http://ninenines.eu</a></font></span><div class=""><div class="h5"><br>
______________________________<u></u>_________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/<u></u>listinfo/erlang-questions</a><br>
</div></div></blockquote></div><br></div></div>