Plataformatec Blog http://blog.plataformatec.com.br Plataformatec's place to talk about Ruby, Ruby on Rails and software engineering Fri, 19 Dec 2014 16:37:02 +0000 en-US hourly 1 http://wordpress.org/?v=4.0.1 Estamos contratando gerentes de projetos http://blog.plataformatec.com.br/2014/12/estamos-contratando-gerentes-de-projeto/ http://blog.plataformatec.com.br/2014/12/estamos-contratando-gerentes-de-projeto/#comments Fri, 19 Dec 2014 11:00:48 +0000 http://blog.plataformatec.com.br/?p=4345 »]]> Você tem perfil para lidar com pessoas e gosta de ágil? Gosta de metodologia ágeis como Scrum, Kanban e Lean?

Temos uma oportunidade para você. Veja abaixo como é ser um gerente de projetos na Plataformatec, e também como é a cultura da nossa empresa.

Sobre a Plataformatec

A Plataformatec é uma empresa de consultoria em desenvolvimento de projetos de software customizado. Usamos Agile, Ruby, Rails, Elixir e métodos de análise estratégica de negócios para ajudar nossos clientes a alcançarem seus objetivos. Nosso time é organizado em equipes compostas por um gerente de projetos e de dois a seis desenvolvedores que encaram os seguintes desafios:

  • entender como um projeto de software se encaixa na estratégia de um cliente e como esse projeto fará com que o cliente alcance seus objetivos
  • ajudar o cliente a definir e esclarecer os objetivos de negócio
  • criar um roadmap em formato de release backlog, pronto para ser transformado em software
  • desenvolver software de modo iterativo, incremental e colaborativo

Por entendermos que a entrega de resultados é de responsabilidade da equipe inteira, não existe hierarquia dentro de uma equipe. Cada pessoa cumpre seu papel da melhor maneira possível para atingir os objetivos do cliente. Não queremos apenas clientes, nosso objetivo é termos fãs.

Como empresa, adoramos compartilhar nosso trabalho e a produção de conhecimento. Mantemos vários projetos open-source, criamos nossa própria linguagem de programação, escrevemos três livros sobre desenvolvimento de software e palestramos em dezenas de eventos de desenvolvimento e agile. Além disso, somos referência mundial na comunidade de Ruby on Rails.

Melhoria contínua sempre esteve presente em nosso DNA. Atuamos no mercado há quase seis anos e desde sempre aplicamos a filosofia agile na empresa inteira, do time de projetos ao RH, do time de vendas ao administrativo.

Nós amamos nosso trabalho.

Sobre a vaga

O que um gerente de projetos faz na Plataformatec

Nossos gerentes de projetos não seguem a chamada linha tradicional. O principal objetivo do nosso GP é potencializar o trabalho do restante da equipe. Para isso, ele mistura atividades de um gerente de projetos, mas também de scrum master, analista de requisitos e proxy de PO.

Algumas atividades típicas do nosso gerente de projetos são:

  • participar do entendimento dos objetivos de negócio do cliente
  • ajudar o cliente a transformar suas ideias em requisitos de software
  • facilitar a comunicação do time com o cliente
  • organizar e acompanhar as releases do projeto
  • ajudar o cliente a otimizar o escopo do projeto para maximizar o valor de negócio no período do projeto
  • planejar e conduzir as cerimônias do agile: planning, daily, grooming, review e retrospectiva
  • monitorar a velocidade de entrega e indicadores de sucesso do projeto
  • retirar impedimentos da equipe

Requisitos para a vaga

  • Educação
    • ensino superior completo em curso da área de computação
    • inglês intermediário (oral e escrito)
  • Experiência
    • 1 ano em gestão de projetos de software
    • 1 ano em gestão de projetos com metodologias ágeis (Scrum, Kanban, Lean etc)
  • Skills
    • apresentar habilidade analítica
    • ser orientado a resultados
    • gostar de aprender
    • ter boa comunicação (verbal e escrita)
    • ser capaz de comunicar informações técnicas para pessoas não técnicas
  • Disponibilidade para trabalhar em SP

Como participar do processo seletivo

Para participar no processo seletivo visite http://plataformatec.com.br/careers e envie seu curriculum. Veja também nossa página no Facebook para conhecer mais sobre o nosso time e nosso escritório.

Nós queremos pessoas que compartilhem dos nossos valores, que se importem com o que fazem e que não cansem de aprender e de se superarem.

Se você compartilha da nossa visão, participe do processo seletivo. Se você conhece alguém que possa se interessar, indique para seu amigo.

]]>
http://blog.plataformatec.com.br/2014/12/estamos-contratando-gerentes-de-projeto/feed/ 0
The pros and cons of 4 deployment process techniques http://blog.plataformatec.com.br/2014/12/the-pros-and-cons-of-4-deployment-process-techniques/ http://blog.plataformatec.com.br/2014/12/the-pros-and-cons-of-4-deployment-process-techniques/#comments Tue, 02 Dec 2014 11:00:34 +0000 http://blog.plataformatec.com.br/?p=4327 »]]> The way of deliver your product code to your customer is commonly called “deployment”. It is an important matter because it will impact in how fast your product will respond to changes and the quality of each change.

Depending on which deployment decision you take, it will impact your team and how you use your version control system.

As a consultancy, we have worked in lots of projects, and together with our customers we have devised many ways to deliver their product to their customers. We have seen some patterns, advantages and challenges on each way, and today I would like to discuss some of them:

  1. The open-source way
  2. The pipeline way
  3. The support branch way
  4. The feature toggle way

The open-source way

In the open-source world most of the times we should maintain many versions of a same product. For example, Ruby on Rails has many versions released, like 2, 3.2, 4.0, 4.1. Bugs happens, new features are created, so news releases must be delivered, but in a set of supported released versions. Still on RoR example, the supported releases are 4.1, 4.0 and 3.2 (http://guides.rubyonrails.org/maintenance_policy.html). But how this releasing works?

The most recent version of the product is maintained on the master branch, the previous major releases have their own branches. On RoR we have the master for the new 4.2 version release, and we still have 4-1-stable, 4-0-stable, 3-2-stable branches. By following this organization we can easily apply changes on the desired versions.

For each release a tag must be created. For example, there’s a tag for RoR 4.0.0, one for 4.1.0 and so on. With tags it is possible to navigate between the released versions and if the worst happens, like losing the “version-stable” branch, it’s easy to create another one from the last released version.

Usually, a web product has just one version to be maintained, so usually we don’t need the “version-stable” branches. We can keep the new product releases on the master branch and generate a tag when we want to package and release a new product version.

When we need a “hotfix” or an urgent feature and the master is not ready yet for production, we can easily create a branch from the latest tagged version, apply the desired changes, create a new tag and release a new version. By the way, using this way you can release any branch you want. All that manipulation of applying commits, merging and creating branches and tags, can be simplified with a powerful version control system like “Git”.

Strong points

  • The flexible package creation and release.
  • It works for large teams, primarily when there are planned releases.

The challenges

  • It requires the infra to be flexible enough to support it.
  • It requires time to control what can be merged on master before the package creation.
  • It will require good ability with the version control system.
  • Manage the release versions.

Common phrases with this approach

  • “Sorry pals, I forgot to apply that hot fix patch on master”. – A developer after releasing a new product version.

The pipeline way

Using a pipeline in your deployment process means you have well defined steps and all steps must be accomplished in order to do a deployment.

Usually the steps are: run the automated tests, release on test/qa environment, create the release tag, release on production. After the steps are defined, you need some software that allows the team to automate some steps and to add the option of requiring a approval for the next step. For example, you only want to release the package to production when your QA team and PO have approved the version on QA.

Having a pipeline means your master branch is always production ready. Any new code inserted on master branch must pass the pipeline, then it is very important that the team and the pipeline to be able to quickly respond to changes.

One important precaution is to be sure that only wanted features are on master, because all code on master will always be deployed on the next software release. I have seen some confusion in this aspect, because some companies are a bit more bureaucratic and have some strict deployment rules.

Per example, a feature can only go to production when the QA team and PO approves. Placing the QA process on pipeline means you’ll put the feature on master that is not ready yet for production. It generates a problem I see regularly with this approach, I’ll call it for now the “release lock”.

Release lock

The release lock can be better understood with an example:

  1. The developers have released on master the Feature A and B.
  2. The QA team finds a BUG on Feature A.
  3. The developers release a Feature C on master
  4. The developers fix the BUG.
  5. PO approves Feature A and B and wants a deploy.

Can we deploy a release with Feature C untested and unapproved by PO? Most of the time the companies answer is no.

Some approaches we can do here are: revert Feature C commits, or simply lock code changes on master and the entire team focus on finishing the release with Feature C.

Of course there are other approaches we can incorporate in the pipeline process, and we’ll see a further discussion about it later in this post.

Strong points

  • With the pipeline it is easier for everyone in the team to understand how the deployment works.
  • The pipeline gives accessibility for anyone in the team to launch a release.
  • Less time managing versioning.

The challenges

  • You lose the flexibility to deploy any branches.
  • In large teams and some companies rules can produce release locks often.

Common phrases with this approach

  • “What? This feature is already in production?” – A member from QA team looking at the version in production.
  • “Hey, stop merging on master! We need a release today!” – The product manager after receiving pressure from stakeholders.

The support branch way

You define a branch as QA or test branch. This branch is useful to test features which aren’t ready for production. For example, if your deployment process needs QA/PO features approval.

With this approach you’ll send the features to support branch. When the feature is approved you send them to the master branch and use the normal deployment process flow. It is important to do a regression test of the merged features on master. When a regression test finds a defect, it is easy to apply them on master, since the master is clear of unwanted features.

While using this approach you should be aware that now you have two points of integration. Resolving the merging conflicts twice is a problem that can happen often, but the most troublesome issue is when the integration on the support branch breaks the application functionality.

When the support branch integration is broken you need to analyze when and where the patch with the fix will be applied.

If you apply the fix on support branch, you must remember to apply it on master again.

The other option is to find out which changes made the features incompatible together. When you find that, you can apply those changes to the branch that doesn’t have those changes. Be aware that depending on the way you do this, you may end up needing to release both features together.

Strong points

  • You can easily apply the support branch in any deployment process you choose.
  • You mitigate the release lock problem.

The challenges

  • Two points of features integration.
  • Requires good abilities with version control system.
  • The support branch maintenance.

Common phrases with this approach

  • “Gosh! I need to fix that merge conflict again.” – Developer merging on master the QA approved feature.

The feature toggle way

Sometimes you are using the feature toggle without knowing you are doing it. For example: when you enable some features only for beta users, or enable some application routes only for some network IPs, or create A/B tests for the users. In general, you are using a feature toggle when your application is restricting in some way the access for some features.

To solve the release lock problem, some teams apply the feature toggle in every feature that needs approval. In this way the team can send unapproved features to production. When the feature is approved, the feature can be turned on without a new deploy. Be aware that sending turned off features to production also means that unapproved feature code will be sended too.

Creating toggles for your features means more code and tests to control what your software does with and without the toggles. Each feature toggle you add increases the complexity and the maintenance cost of your codebase.

Thus, it is important to remove them after the feature approval before it starts damaging your software. I know what you’re thinking, yes, it is true, most of the times the QA/PO team want to test the toggle removal and you might face the release lock problem again.

Strong points

  • You can use the pipeline with only one point of integration.
  • You reduce the release lock problem.

The Challenges

  • You may increase the cost of development because of maintenance and removal of feature toggles.
  • The feature toggle management.

Common phrases with this approach

  • “What this method does?” – A developer asking for his pal.
  • “It depends, which toggles are on?” – The answer of the first question.

Conclusion

Most of the challenges of each deployment process requires team engagement and organization. It’s hard to decide which one is better, because it fully depends on how your team adapt to the process.

Each person perceive problems in different ways. What is a huge matter for someone, for the other is just a small itch. But if you still want answers for “What is the best option?”, I would say it is the same answer for “Which challenge your team will endure more?”.

Given that you prefer one deployment process over the others, I still think that no one should be attached totally with one process forever. Your problems can change, your team can change, your company rules can change, your application can change. Therefore, your deployment process should change together to deal with the new challenges. You can change your deployment in many ways, for example mixing ideas from each the of processes we discussed.

I’m curious to know how your team deliver features. If you use one of these options, if you mix them or if you do something different. If you want share this knowledge, please leave a comment below.












]]>
http://blog.plataformatec.com.br/2014/12/the-pros-and-cons-of-4-deployment-process-techniques/feed/ 5
XSS vulnerability on Simple Form http://blog.plataformatec.com.br/2014/11/xss-vulnerability-on-simple-form-2/ http://blog.plataformatec.com.br/2014/11/xss-vulnerability-on-simple-form-2/#comments Wed, 26 Nov 2014 15:18:28 +0000 http://blog.plataformatec.com.br/?p=4316 = 2.0.0 Not affected: < 2.0.0 Fixed versions: 3.1.0, 3.0.3, 2.1.2 Impact When Simple Form renders an error message it marks the text as being HTML safe, even though it may contain HTML tags. In applications where the error message can be provided ... »]]> There is a XSS vulnerability on Simple Form’s error options.

  • Versions affected: >= 2.0.0
  • Not affected: < 2.0.0
  • Fixed versions: 3.1.0, 3.0.3, 2.1.2

Impact

When Simple Form renders an error message it marks the text as being HTML safe, even though it may contain HTML tags. In applications where the error message can be provided by the users, malicious values can be provided and Simple Form will mark them as safe.

Changes at the behavior

To fix this vulnerability error messages are now always escaped. If users need to mark them as safe they will need to use explicitly the :error option:

f.input :name, error: raw('My error')

Releases

The 3.1.0, 3.0.3 and 2.1.2 releases are available at the regular locations.

Workarounds

There are no feasible workarounds for this issue. We recommend all users to upgrade as soon as possible.

Patches

To aid users who aren’t able to upgrade immediately we have provided patches. They are in git-am format and consist of a single changeset.

Credits

Thanks to Jake Goulding, from WhiteHat Security and Nicholas Rutherford from Medify Ltd. for reporting the issue and working with us in a fix.












]]>
http://blog.plataformatec.com.br/2014/11/xss-vulnerability-on-simple-form-2/feed/ 0
Converting Erlang code into Elixir http://blog.plataformatec.com.br/2014/11/converting-erlang-code-into-elixir/ http://blog.plataformatec.com.br/2014/11/converting-erlang-code-into-elixir/#comments Wed, 12 Nov 2014 11:00:42 +0000 http://blog.plataformatec.com.br/?p=4303 »]]> When you are new to any language, you probably want to run some existing code just to see how it works. Achieving success while trying new things is important, because it helps fueling your interest.

The number of code examples in Elixir is increasing, but sometimes you will have to read some Erlang code. Recently, I wanted to play a little bit with Cowboy HTTP Server, which is written in Erlang. The Cowboy repo has a lot of small examples presenting the features which is provided by it. When I tried to convert one of them to Elixir, it wasn’t as simple as I expected, since I’m not so familiarized with the language yet.

When converting, you may get into some misleading code that will not work as you expected at first. So, I’m going to present a transcoding of Cowboy WebSocket server example from Erlang to Elixir, so that you can learn some of the details that exists in the process of porting Erlang code into Elixir code.

This will not be a tutorial explaining how that Cowboy example works, it’s just about how to convert it to Elixir. Also, I’m not going to show how it could be done in idiomatic Elixir, the goal here is to translate Erlang code into Elixir the simplest way possible.

So let’s start!

Creating the project

Create a project called ws_cowboy with the following command:

mix new ws_cowboy
cd ws_cowboy

After that we are going to change/create 4 files:

  • mix.exs: declares the dependencies in the project and the application module to run
  • lib/ws_cowboy.ex: the application module that setups the cowboy routes and http server
  • lib/ws_handler.ex: handles a WebSocket request connection
  • lib/ws_supervisor.ex: supervisor for Cowboy server

Also, copy the whole priv directory from the Cowboy example to the project’s root dir.

The project definition

In the mix.exs file we are going to add the Cowboy dependency and also configure the module application, in this case WsCowboy.

defmodule WsCowboy.Mixfile do
  use Mix.Project

  def project do
    [app: :ws_cowboy,
     version: "0.0.1",
     elixir: "~> 1.0",
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type `mix help compile.app` for more information
  def application do
    [applications: [:logger, :cowboy],
     mod: {WsCowboy, []}]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type `mix help deps` for more examples and options
  defp deps do
    [{:cowboy, "~> 1.0.0"}]
  end
end

Configuring the HTTP application

Here is the transcode of websocket_app.erl file to the ws_cowboy.ex file:

defmodule WsCowboy do
  @behaviour :application

  def start(_type, _args) do
    dispatch = :cowboy_router.compile([
      {:_, [
        {"/", :cowboy_static, {:priv_file, :ws_cowboy, "index.html"}},
        {"/websocket", WsHandler, []},
        {"/static/[...]", :cowboy_static, {:priv_dir, :ws_cowboy, "static"}}
      ]}
    ])
    {:ok, _} = :cowboy.start_http(:http, 100, [{:port, 8080}],
                                  [{:env, [{:dispatch, dispatch}]}])
    WsSupervisor.start_link
  end

  def stop(_state) do
    :ok
  end
end

If you never read any Erlang code and you came from a language like Ruby, you might get confused on basic things. So, let’s go through some of the details of porting websocket_app.erl to the ws_cowboy.ex.

Erlang files represents a module, in Elixir it is the same thing, but in this case we use the defmodule macro. Erlang modules can be accessed using :<module_name>, so in this case we are defining that this module has the application behaviour.

Different from other languages like Ruby, lowercase names aren’t variables in Erlang, but atoms, while in Elixir atoms look the same as Ruby symbols. So, we scanned every lowercase names and replaced them with :<name>.

Upper case names in Erlang aren’t constant but variables, so we changed them to lowercase. It is good to do this in inverse order to avoid mixing variables and atoms.

During the process of converting this file, there was a line making the application not work and I spent some time trying to figure out what was wrong. In Ruby, 'foo' and "foo" are both strings, but in Elixir and Erlang they are different things. The single quote in Erlang is an atom (symbol), so the '_' line must be converted to :_ in Elixir. If you miss this little detail, unfortunately it will compile and run, but Cowboy will always return a 400 status code.

Except that, everything is pretty straightforward, the only detail is the :cowboy_static definition that you have to replace with your dir app name, in this case :ws_cowboy.

To transcode function calls, you just have to replace the : with ., like in Ruby.

Handling the WebSocket connection

You can read more about how Cowboy handles WebSocket here. Here’s the transcode of the file ws_handler.erl to ws_handler.ex:

defmodule WsHandler do
  @behaviour :cowboy_websocket_handler

  def init({:tcp, :http}, _req, _opts) do
    {:upgrade, :protocol, :cowboy_websocket}
  end

  def websocket_init(_transport_name, req, _opts) do
    :erlang.start_timer(1000, self(), "Hello!")
    {:ok, req, :undefined_state}
  end

  def websocket_handle({:text, msg}, req, state) do
    {:reply, {:text, "That's what she said! #{msg}"}, req, state}
  end

  def websocket_handle(_data, req, state) do
    {:ok, req, state}
  end

  def websocket_info({:timeout, _ref, msg}, req, state) do
    :erlang.start_timer(1000, self(), "How' you doin'?")
    {:reply, {:text, msg}, req, state}
  end

  def websocket_info(_info, req, state) do
    {:ok, req, state}
  end

  def websocket_terminate(_reason, _req, _state) do
    :ok
  end
end

Following the steps done in the previous file, there is no secret on this one. The only detail is that the Erlang version used binary notation for strings, but in Elixir you can use just "string" normally. Also, you can use string interpolation "That's what she said! #{msg}".

Writing the supervisor

Now there’s just one translation missing, from websocket_sup.erl to ws_supervisor.ex. Here we just used __MODULE__ instead of the Erlang ?MODULE:

defmodule WsSupervisor do
  @behaviour :supervisor

  def start_link do
    :supervisor.start_link({:local, __MODULE__}, __MODULE__, [])
  end

  def init([]) do
    procs = []
    {:ok, {{:one_for_one, 10, 10}, procs}}
  end
end

Running your server

Running your server is pretty easy, just run the mix run --no-halt command and check http://127.0.0.1:8080 in your browser.

Conclusion

The goal of this post was to show an example of how to port Erlang code into Elixir code. The result we got is the simplest translation possible, it was not my idea to write idiomatic Elixir here. For example, in Elixir you would not use Erlang’s supervisor module, but rather the Elixir’s supervisor.

I hope you could get the picture of how it is to translate Erlang code into Elixir, how it’s not so hard and some of the details that you must pay attention while doing it.

If you are interesting in learning more about Elixir, check out the getting started page.

Do you had any issues when starting to play with Elixir that you cracked your head to figuring out why it didn’t work? Share your experience and doubts with us!












]]>
http://blog.plataformatec.com.br/2014/11/converting-erlang-code-into-elixir/feed/ 0
How to serialize Date and DateTime to JSON without losing information http://blog.plataformatec.com.br/2014/11/how-to-serialize-date-and-datetime-without-losing-information/ http://blog.plataformatec.com.br/2014/11/how-to-serialize-date-and-datetime-without-losing-information/#comments Wed, 05 Nov 2014 11:00:36 +0000 http://blog.plataformatec.com.br/?p=4289 »]]> When building APIs, it is pretty common to use JSON as a serialization format. JSON defines serialization for boolean, number and string, but not for date/datetime values.

What most serializers do with Date and DateTime values is to use the ISO8601 standard. For example:

# Date format
2011-07-14

# DateTime format
2011-07-14T19:43:37+0100

However, you should be aware that information is lost when you use the Date format. That happens because a Date value might differ between different timezones. Let me give you an example:

  • a request was issued at 2011-07-14 T01:00:00Z (UTC) from Brazil (UTC-0300) to a service in UTC
  • if the time the request was created is exposed as a Date, it would return the value as 2011-07-14
  • but from the client’s perspective in Brazil, the correct date is 2011-07-13, since at the moment of that request was issued, the local time in Brazil was 2011-07-13 T22:00:00-0300

If this information is used only inside your app, within the same timezone, you would have no problems. But, if you need to make this information available through a public API, one of your API’s consumers might recover an incorrect value.

So, from this experience, any date value that will be shared and consumed by different clients should be represented as date time with explicit timezone or using the Unix time format. That way, it is up to the client to treat the data properly.

Here is an example of an API that returns a subscription period in the right way:

{
  period_start_date: 1409175049, # Unix time
  period_end_date: 2014-09-27T18:30:49-0300 # ISO8601
}

# Time.at(1409175049)
# DateTime.parse(“2014-09-27T18:30:49-0300”)

The options above have the advantage that both are unambiguous and sortable. You may choose between one or another based on the fact that the timezone option is easier for human comprehension. But remember that Timezones are a presentation-layer problem, so if you just need to pass data around, Unix time is preferable.

Have you ever had this serialization problem or any other that caused information to be lost? If you have questions or any experience to share, please, leave a comment below.












]]>
http://blog.plataformatec.com.br/2014/11/how-to-serialize-date-and-datetime-without-losing-information/feed/ 4
Playing with Elixir and Go concurrency models http://blog.plataformatec.com.br/2014/10/playing-with-elixir-and-go-concurrency-models/ http://blog.plataformatec.com.br/2014/10/playing-with-elixir-and-go-concurrency-models/#comments Wed, 29 Oct 2014 11:00:19 +0000 http://blog.plataformatec.com.br/?p=4271 »]]> In Go Concurrency Patterns talk, Google I/O 2012, presenter Rob Pike demos some great concurrency features from Go, like channels and Go routines, and how it can be used to build fast, replicated and robust software.

Concurrency patterns is a very interesting topic but there was one statement in special that got me thinking:

“The models are equivalent but express things differently.”

This is about the distinction between Go channels and its cousin Erlang messages passing approach to communicating between processes.

Implementing Go channels with Elixir processes and messages

Before discovering that it has been done before, I wrote some simple Elixir code to play with the theoretical equivalence between those two models.

Notice that this implementation is not meant to be complete, nor efficient and is not recommended for production software. Don’t do it at home.

defmodule GoChannel do
  def make do
    spawn(&GoChannel.loop/0)
  end

  def write(channel, val) do
    send(channel, { :write, val})
  end

  def read(channel) do
    send(channel, { :read, self })

    receive do
      { :read, channel, val} -> val
    end
  end

  def loop do
    receive do
      { :read, caller } -> receive do
        { :write, val } -> send(caller, { :read, self, val }); loop
      end
    end
  end
end

Some tests

defmodule GoChannelTest do
  use ExUnit.Case

  test "write and read to a channel" do
    channel = GoChannel.make
    GoChannel.write(channel, 'hello')
    assert GoChannel.read(channel) == 'hello'
  end

  test "write and read preserves order" do
    channel = GoChannel.make
    GoChannel.write(channel, 'hello')
    GoChannel.write(channel, 'world')
    assert GoChannel.read(channel) == 'hello'
    assert GoChannel.read(channel) == 'world'
  end
end

This pseudo channel implementation relies on a combination of messages between processes to simulate the original FIFO behaviour of channels.

The same way one could pass a channel as parameter to other functions, since it’s a first-class citizen, we could pass the result of GoChannel.make, since it’s a PID, which in turn is a first-class citizen in Elixir.

Back to concurrency patterns

The first pattern demonstrated in Rob’s talk was fanIn, where two channels were combined into a single one.

func fanIn(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    go func() { for { c <- <-input1 } }()
    go func() { for { c <- <-input2 } }()
    return c
}

We could translate this code to Elixir, using our borrowed abstraction:

defmodule Patterns do
  def fan_in(chan1, chan2) do
    c = GoChannel.make

    spawn(loop(fn -> GoChannel.write(c, GoChannel.read(chan1)) end))
    spawn(loop(fn -> GoChannel.write(c, GoChannel.read(chan2)) end))

    c
  end

  defp loop(task) do
    fn -> task.(); loop(task) end
  end
end

Some tests:

defmodule PatternsTest do
  use ExUnit.Case

  test "fan_in combines two channels into a single one" do
    chan1 = GoChannel.make
    chan2 = GoChannel.make

    c = Patterns.fan_in(chan1, chan2)

    GoChannel.write(chan1, 'hello')
    GoChannel.write(chan2, 'world')

    assert GoChannel.read(c) == 'hello'
    assert GoChannel.read(c) == 'world'
  end
end

We could go even further in this mimic game and try to implement the select statement, but that would be a very extensive one. First let’s reflect a little about composing more complex functionality with channels.

Channels as Streams

From a consumers perspective, reading from a channel is like getting values out of a stream. So, one could wrap a channel in a stream, using the Stream.unfold/2 function:

  def stream(channel) do
    Stream.unfold(channel,
                  fn channel -> {read(channel), channel} end)
  end

This function returns a Stream, which gives us lots of power to compose using its module functions like map/2, zip/2, filter/2, and so on.

One test to demo that:

  test "compose channel values with streams" do
    channel = GoChannel.make
    stream = GoChannel.stream(channel)

    GoChannel.write(channel, 1)
    GoChannel.write(channel, 2)
    GoChannel.write(channel, 3)

    doubles = Stream.map(stream, &(&1 * 2)) |> Stream.take(2) |> Enum.to_list

    assert doubles == [2, 4]
  end

Reviewing comparisons

The following quote from Rob Pike's talk is one common analogy used to compare channels and Erlang concurrency models:

“Rough analogy: writing to a file by name (process, Erlang) vs. writing to a file descriptor (channel, Go).”

I think analogies are really useful for communication but I believe they work better as the start of an explanation, not its summarization. So I think we could detail differences a little further.

For example, PIDs are not like “file names” since they are anonymous and automatically generated. As we just saw, PID is a first-class citizen and in the language’s perspective, is just as flexible as a channel.

I would say that channels abstraction reinforce isolation from producer to consumer, in the sense that Go routines writing to a channel doesn't know when nor who is going to consume that information. But it doesn't mean that using processes and messages one could not achieve the same level of isolation, as we just demoed.

On the other hand, identifying producers and consumers explicitly allow us to monitor and supervise them, allowing language like Erlang and Elixir to leverage the so-called supervision trees useful for building fault-tolerant software in those languages.

Besides been an interesting exercise to mimic Go’s way of solving problems, one should be aware that Erlang and Elixir have their own abstractions and patterns for handling concurrency.
For example, one could use the GenEvent module to implement a pub/sub functionality.

Elixir, Erlang and Go have some common goals, like the ones cited in the first paragraph of this post, but they also have their specifics. Embracing differences provides better results in the long term because it helps leverage each language power.

References












]]>
http://blog.plataformatec.com.br/2014/10/playing-with-elixir-and-go-concurrency-models/feed/ 0