To start development on a new Erlang module that supports concurrent processing, I wrote myself a template, that is mostly inspired by the template from Joe Armstrong and his book Programming Erlang - Software for a Concurrent World.

%% start
%% @spec start() -> pid()
start() ->
  % explicit MFA (module, function, args list) enables dynamic code upgrades
  spawn(ctemplate, loop, [[]]).
%% remote call
%% @spec rpc(pid(), any()) -> any()
rpc(Pid, Request) ->
  Pid ! {self(), Request},
    % Pid is in the pattern match to avoid grabbing messages from all 
    % processes ...
    {Pid, Response} ->
%% receive loop handler
%% @spec loop(any()) -> none()
loop(X) ->
    Any ->
      io:format("Received:~p~n", [Any]),
      % tail recursion: this should be the last call, 
      % so it won't consume any stack space

I developed the template from the book a bit further and used MFA (Module, Function, Argument List) in the spawn call to enable dynamic code upgrades. In the top you can see, that all functions will be exported (that means, callable from other modules or the shell). This is only for debugging purposes. As a default, the loop will just print out, what has been received from the client process.

But in most cases, it would be much better to have a look at the OTP behaviours :)