Fork me on GitHub

PHP

A maneira errada

Última atualização: 2018-11-29
cartoon

Bem-vindo

No mundo da programação PHP um conjunto de tendências estão sendo massivamente propagadas por algumas pessoas (em seus livros e websites) como “PHP Moderno” enquanto todas as outras abordagens são vistas como atrasadas, estúpidas, ou simplesmente erradas.

Essas pessoas parecem trabalhar incansavelmente no sentido de conseguir que as outras pessoas sigam sua maneira de fazer as coisas.

Esse website foi criado numa tentativa de apresentar uma visão pragmática sobre a programação PHP. Uma visão ditada pela experiência e consequências práticas ao invés de tendências populares, teorias, ou dogmas acadêmicos.

O website PHP - The Wrong Way é um documento livre e continuará sendo atualizado com mais informações assim que estiverem disponíveis.

Sinta-se livre para contribuir.

Traduções

O perigo do extremismo

Um problema com regras e diretrizes na programação é que elas geralmente só servem a um propósito em um contexto específico. Saindo desse contexto, uma boa regra pode se tornar uma regra horrível. De fato, toda boa regra se torna ruim quando levada ao extremo.

Isso é importante entender porque muitos princípios e regras do desenvolvimento de software desenvolvidas ao longo do tempo e apresentadas por diferentes pessoas frequentemente se tornam mal utilizadas nas mãos de extremistas.

Experience has taught that misuse of general rules and guidelines always results in complication, lack of security, error-prone results, and in some cases complete and utter disaster.

A experiência ensinou que o uso indevido de regras e diretrizes gerais sempre resulta em complicações, falta de segurança, resultados propensos a erros e, em alguns casos, desastre total e completo.

O princípio KISS, que é um acrônimo para “Keep It Simple, Stupid”, é um bom e extremamente sábio princípio que geralmente é visto por pessoas experientes como um conselho muito bom a seguir, mas mesmo este grande princípio torna-se um perigo para um projeto, se levado ao extremo. Existe tal coisa como “muito simples” resultando em falta de funcionalidade necessária.

A maneira errada: Aplicação religiosa de regras e diretrizes. Thumbs down

Sempre use um framework

All general purpose PHP frameworks suck!

Rasmus Lerdorf

In the PHP community a really bad trend has become de-facto standard for developing web applications and that is by the usage of a popular general purpose framework.

This trend has emerged and become popular not because it in any way improves the result of the developing process, or because it is the right thing to do from a technology and architectural point of view. This trend has become popular because some of the developers of frameworks have managed to sweep away the masses with their polemic against programming from the ground up with stanzas like “Don’t re-invent the wheel!” and “Don’t do it yourself, others are more skillful than you”.

Many of today’s programmers completely ignore the fundamental principles of sound programming and they spend a large amount of time fantasizing new layers of complexity in order to appear more clever, more cool, and more acceptable by whomever they regard as their peers.

These people seems to be infatuated by the thought of having other people follow their “way of doing things”, becoming some kind of PHP community leaders, and having other people use their latest “hip” Open Source tools, that they forget to make sure that the advice they are giving is sound and solid.

In the software industry you can compare a pre-built house to a general purpose framework. Building software using general purpose frameworks doesn’t make you a coder or a programmer any more than putting together a pre-built house makes you a carpenter.

On this website, we differentiate between frameworks and libraries in the following way:

In the world of Python and Ruby, building websites from the ground up is tiresome because neither Python nor Ruby was originally created to build websites. As a result general-purpose frameworks such as Django and Ruby on Rails quickly became popular for building websites in these languages.

PHP on the other hand was created in the beginning by Rasmus Lerdorf as a set of tools written in C that would enable you to easily and quickly develop dynamic HTML. As such PHP was, and still is, a framework in and of itself.

PHP has evolved massively since then and today PHP can be used for much more than building HTML and websites, but viewing PHP as a sort of framework in itself is not wrong. PHP is by nature a layer of abstraction for developing web applications written entirely in a procedural C.

Using a library within your project is only natural. PHP itself comes bundled with a set of libraries that you can use to extend your own code. PDO for example is a lightweight library that provides a consistent interface for accessing databases in PHP.

Using a framework on top of PHP on the other hand is another matter entirely.

When you use a framework in PHP you add a layer of abstraction on top of yet another layer of abstraction, one that was already in place for you to use to begin with. The added layer of abstraction that the framework provides may simply serve to organize your code into a pre-fixed set of patterns, or it may add even more complexity by intertwining hundreds or even thousands of classes and methods into a nightmare of dependencies, either way you’re adding layers of complexity to your code that isn’t needed!

All experience starts with the interface. The interface experience is the result of the underlying technology and the amount of layers of abstraction. The more abstraction you use, the less efficient the interface becomes and the more error-prone the application becomes. The higher the abstraction, the more detail and efficiency is lost.

Understand this clearly: The ideal number of lines of code in any project is as few as possible whilst being as clear and readable as possible!

What everyone doesn’t need is a general purpose framework. Nobody has a general problem, everyone has a very specific problem they are trying to solve.

Rasmus Lerdorf

Some companies began listening to the hype about PHP frameworks and they started their next projects using one of these popular general purpose frameworks only to end up in a disaster. Not only did they discover that the general purpose framework was really bad at solving their very specific need, but it was also extremely slow in doing so. It was impossible to scale and as a result they started ripping the framework apart in a desperate attempt to pull out all those things they really didn’t need.

Always use the pragmatic approach:

Action or policy dictated by consideration of the immediate practical consequences rather than by theory or dogma.

– Collins English Dictionary, Complete and Unabridged, 12th Edition 2014

The wrong way: Always use a framework on top of PHP. Thumbs down

Sempre use padrões de projeto

I have this big allergy to ivory-tower design and design patterns. Peter Norvig, when he was at Harlequin, he did this paper about how design patterns are really just flaws in your programming language. Get a better programming language. He’s absolutely right. Worshiping patterns and thinking about, “Oh, I’ll use the X pattern.”

– Brendan Eich in Coders at work - Reflections on the Craft of Programming

In software engineering, a design pattern is a reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or an idea for how to solve a problem that can be used in many different situations. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved.

PHP supports imperative, functional, object-oriented, procedural, and reflective paradigms. PHP is a huge toolbox with lots of different tools that makes it possible to solve many problems in many different ways - not just one way.

PHP is all about freedom, fast and scalable solutions, and having many different ways to deal with problems.

When we try to improve ourselves, and in this case more specifically our code, we sometimes get hung up in the philosophy of a particular pattern or idea and tend to forget to think practically.

When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I’m using abstractions that aren’t powerful enough - often that I’m generating by hand the expansions of some macro that I need to write.

Paul Graham

We shouldn’t get to caught up in the philosophy or idea behind a specific pattern or solution. Our main concern is to keep the code as easy to navigate and understand as possible and as a result easy to maintain and easy to keep secure.

We must also remember that there exists such a thing as an anti-pattern. It is a pattern that may be commonly used but is ineffective and/or counterproductive in practice.

I think patterns started off as generally recognized best solutions for common problems. But now that they have been around for a while and we have experienced applications being made ten times more complicated than they need to be because people try to cram in all the patterns that they have read about (“my application is well architected, because it is loaded to the gills with patterns.”) my impression of the value of the pattern has shifted a bit.

– Paul Weaton in Evil Design Patterns

Always use the pragmatic approach:

Action or policy dictated by consideration of the immediate practical consequences rather than by theory or dogma.

– Collins English Dictionary, Complete and Unabridged, 12th Edition 2014

The wrong way: Looking for a pattern to solve a problem. Thumbs down

Sempre use orientação a objetos

The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.

– Joe Armstrong in Coders at work - Reflections on the Craft of Programming

Abstraction is powerful. What I’m really allergic to, and what I had a reaction to in the ’90s, was all the CORBA, COM, DCOM, object-oriented nonsense. Every startup of the day had some crazy thing that would take 200.000 method calls to start up and print “Hello world”. That’s a travesty! You don’t want to be a programmer associated with that sort of thing.

– Brendan Eich in Coders at work - Reflections on the Craft of Programming

Many software developers, and many companies, feel that object-oriented programming is the only reasonable way to develop software today. Any one who argues against object-oriented programming is immediately made conscious of the fact that they are arguing against the “conventional wisdom” of the industry.

On programming blogs and forums, there are a great many people who defend object-oriented programming, and who feel certain that they know what they are talking about, despite the lack of any standard definition!

The fact is that so-called object-oriented programming as such often inflicts a heavy burden of unneeded complexity!

As computer scientists and programmers we must learn to set aside prejudices and find the best solution to a given problem.

Today, one of the main strengths of PHP is its support for both imperative, functional, object-oriented, procedural, and reflective paradigms. PHP is a huge toolbox with lots of different tools that makes it possible to solve many problems in many different ways - not just one way!

As soon as we try to force-feed different problems within an application to a single specific programming paradigm, we’re not thinking creatively and we’re not working efficiently!

A small history lesson

One of the greatest ways to understand a specific programming paradigm is to look at how it first evolved. What was the reason for its development? What problems existed with other programming paradigms that needed a new way of thinking? Was it a real world problem or simply an academic problem? And how has it since evolved?

It doesn’t matter what person X says or what definition person Y gives, what matters in the context of paradigms is the history that made them.

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.

C.A.R. Hoare

In the past, before the advent of object-oriented programming, around the end of the fifties, much software was developed using programming languages that emphasized unstructured programming, sometimes referred to as first- and second-generation languages. Unstructured programming (or non-structured programming) is historically the earliest programming paradigm. It was heavily criticized for producing “spaghetti” code.

There are both high- and low-level programming languages that use non-structured programming. These include early versions of BASIC, COBOL, MUMPS, JOSS, FOCAL, TELCOMP, machine-level code, early assembler systems (those without procedural meta operators) and some scripting languages.

A program in a non-structured language usually consists of sequentially ordered commands, or statements, usually one in each line. The lines are usually numbered or may have labels which allows the flow of execution to jump to any line in the program (like with the unpopular GOTO statement).

Then, in the sixties, structured programming emerged - mainly due to the famous letter by Edsger W. Dijkstra Go To statements considered harmful.

Structured programming is a programming paradigm that improves the clarity, quality, and development of software by making use of subroutines, block structures and loops. This is in contrast to using simple jumps such as the GOTO statement.

Later, procedural programming was derived from structured programming. Procedural programming is based upon the concept of “procedure call”. A “procedure call” is just another name for a “function call”. Procedures are also known as routines, subroutines or methods. A procedure simply contain a series of computational steps to be carried out. Any given procedure might be called at any point during a programs execution, including by other procedures or itself.

In the beginning all procedures were available to any part of a program as global data. In small programs this didn’t present a problem, but as things got more complicated and as the size of the program grew, small changes to one part of the program greatly effected many other parts.

Nobody was planning for changes in the program and lots of dependencies existed. A minor change to one procedure would result in a cascade of errors in lots of other procedures that depended on the original code.

A new technique evolved that allowed data to be divided into separated scopes called “objects”. Only specific procedures belonging to the same scope could access the same data. This is called data hiding or encapsulation. The result was much better organized code.

In the beginning objects were not called objects, they were just viewed upon as separate scopes. Later when dependencies were reduced and connections between procedures and variables inside these scopes were viewed upon as isolated segments, the result gave birth to the concepts of “objects” and “object-oriented programming”.

Later, mainly due to the development of Java, certain “buzzwords” arose and “a procedure” or “a function” was no longer called a function, but was renamed “a method” when it resided inside a separate scope. Variables were also no longer called “variables”, but were renamed “attributes” when they resided inside a separate scope.

So an object is in essence simply a collection of functions and variables now called “methods and attributes”.

The way methods and attributes are kept isolated inside a separate scope is by the usage of “a class”. A class, once it is instantiated, is called an object.

Objects can reference each other and by such a reference the methods (functions) inside can “communicate” with each other. Objects can also “inherit” methods from other objects thereby extending such, this is called “inheritance”. It is a way to reuse code and allow independent extensions of the software via public classes and interfaces. The relationships of objects give rise to a hierarchy. Inheritance was invented in 1967 for the programming language Simula 67.

Objects can also inherit methods from other objects and “override” these with added or changed functionality, this is called “polymorphism”.

How these different ideas are implemented vary greatly from programming language to programming language.

Object-oriented programming is about organizing code in another way than before. It is an extension of procedural programming and it is about hiding data (encapsulation) and avoiding a global scope. It is about extending functions by “borrowing” their blueprints without actually affecting the original code (inheritance). And it is about overriding functions without affecting the original code (polymorphism).

The object-oriented model makes it easy to build up programs by accretion. What this often means, in practice, is that it provides a structured way to write spaghetti code.

– Paul Graham in Ansi Common Lisp

The wrong way: Always use object-oriented programming. Thumbs down

Ter medo do código de outras pessoas

Um argumento frequentemente expresso para o uso de um framework é que as pessoas não querem lidar com códigos que foram escritos do zero por outras pessoas.

Esta é, no entanto, uma mentalidade estranha, encontrada principalmente entre web developers na comunidade PHP, que exala uma falta de profissionalismo e experiência.

Escrever software e lidar com o código de outras pessoas é normal, é parte do trabalho diário de quem programa profissionalmente, não é algo para se ter medo.

Quem programa profissionalmente não olha para o código de outras pessoas e começa a se lamentar sobre como está à mercê completa do ex-programador, que talvez não esteja mais associado à empresa ou projeto, e se apenas o antigo programador tivesse usado uma estrutura A ou framework B o dia teria sido salvo.

Esta não é a mentalidade de quem programa de maneira profissional. Ninguém faz isso.

Talvez a facilidade de entrada no desenvolvimento web do PHP desempenhe um papel nesse tipo de mentalidade. Independentemente disso, é um sinal de uma pessoa estar na linha errada de trabalho.

Uma grande parte da programação lida com pessoas que precisam trabalhar com código de outras pessoas. Faz parte do trabalho tentar melhorar a base de código existente e, por vezes, isso envolve uma reescrita completa.

Tome nota de pessoas que são grandes referências da programação, leia o livro Coders at work - Reflections on the Craft of Programming.

Algumas das bases de código maiores e mais bem sucedidas do mundo são bases de código que foram desenvolvidas por centenas de pessoas que nunca se conheceram, bases de código desenvolvidas sem o uso de qualquer tipo de framework, bases de código feitas inteiramente em uma linguagem de programação procedural sem o uso de qualquer coisa, mas o paradigma procedural, e eles não sonham em fazê-lo de forma diferente.

O Kernel do Linux consiste em mais de 20 milhões de linhas de código que foram inteiramente escritas utilizando programação procedural por mais de 14.000 pessoas sem o uso de qualquer tipo de framework.

Os diferentes sabores BSD e a maioria do Linux GNU foram escritos inteiramente usando programação procedural sem o uso de qualquer tipo de framework.

O mesmo vale para centenas de projetos de código aberto em torno desse mundo que acabaram sendo abandonados pela (s) pessoa (s) que os desenvolvia (m) originalmente apenas para serem escolhidos por outras pessoas habilidosas. Muitos desses projetos tinham pouca documentação (se é que tinham alguma), nenhum comentário na base de código e nenhuma orientação ou ajuda para oferecer.

Toda a base de código PHP é feita em C, uma linguagem de programação puramente procedural, sem o uso de qualquer tipo de framework.

A base de código PHP inteira é feita em C, uma linguagem de programação processual pura, sem o uso de qualquer tipo de framework que assim sempre.

Sempre que você define uma classe em PHP ou sempre que usa o seu framework PHP favorito, sua aplicação roda sobre o trabalho puramente procedural de outra pessoa!

Claro, existem coisas como código horrível, código que talvez não tenha sido projetado desde o início, ou código que talvez tenha crescido demais, mas o cliente não queria lidar com uma reescrita, código tão ruim você não pode fazer cara ou coroa dele por mais tempo, mas nenhum tipo de framework teria evitado essa situação. Este é frequentemente o processo natural de crescimento de um programa. Eventualmente, qualquer tipo de estrutura teria sido destruída de qualquer maneira.

E com certeza existe código spagetti horrível, mas ninguém produz um código horrível de propósito. Às vezes isso é resultado da falta de experiência, muitas vezes é culpa do cliente porque ele altera as especificações várias vezes no meio do desenvolvimento, em qualquer um dos dois casos, mesmo que um framework seja usado, o resultado ainda seria código spagetti, e não importa quanto do paradigma orientado a objeto fosse usado, o resultado ainda seria código spagetti.

Como pessoas desenvolvedoras, tentamos evitar essas situações, mas isso é normal, isso é a arte da programação, isso é parte do que significa ser uma pessoa que programa!

O caminho errado: Ter medo do código de outras pessoas. Thumbs down

Following the PHP-FIG standards religiously

The FIG stands for “Framework Interoperability Group”.

The PHP-FIG was created by a number of framework developers at php|tek in 2009. Since then various other members have applied and been voted in, increasing the size of the group from the first 5 to over 20.

A lot of controversy exists regarding the PHP-FIG. Some people consider the PHP-FIG the best thing that has happened to the PHP community since PHP itself while others considers the group as something best to be forgotten.

One of the problems with PHP-FIG is that it presents itself like this in their FAQ:

The idea behind the group is for project representatives to talk about the commonalities between our projects and find ways we can work together. Our main audience is each other, but we’re very aware that the rest of the PHP community is watching. If other folks want to adopt what we’re doing they are welcome to do so, but that is not the aim. Nobody in the group wants to tell you, as a programmer, how to build your application.

However, when we view the work of several members of the group, we can clearly see that the objective is quite contrary to the above statement. These members work tirelessly in an attempt to make PHP-FIG become an accepted “PHP standards group”, which also was the original name of the group. They do this by classifying the work of the PHP-FIG as “Modern PHP” in their books, on their websites, blog-posts, forums, etc., and by classifying other ways as backwards.

One of the problems with the PHP-FIG is that even though many frameworks and Open Source projects has adopted several of their standards, these standards mainly deal with problems from a “framework perspective”, which renders them pretty unusable in many real-life industry situations.

Many people develop software for the industry that has to be extremely efficient, secure, and cost-effective, software that customers are willing to buy and use. They cannot be bothered with standards that has to conform to the needs of framework fanatics. If they tried to be it would be a disaster for business.

If some kind of standards group needs to be created it has to reflect the interests of the entire PHP community, not just framework and Open Source CMS project developers. It has to be represented by the developers of the PHP programming language itself and it has to be represented by a much larger membership with the right to vote.

If you choose to adopt the standards developed by the PHP-FIG, you have to understand that some of these standards - such as the autoloader standards PSR-0 and PSR-4 and several other standards - has a direct effect upon how you code your software.

Many industries demand highly scalable, run-time critical, and cost-effective software that simply cannot be developed using these standards of the PHP-FIG.

The wrong way: Following the PHP-FIG religiously. Thumbs down

Negligenciar a segurança

O problema com os programadores é que você nunca sabe dizer o que eles estão fazendo, até que seja tarde demais.

– Seymour Cray on defprogramming.com

A programação segura é a prática de escrever programas que são resistentes ao ataque de pessoas maliciosas ou outros programas. A programação segura ajuda a proteger os dados contra roubo ou corrupção. Além disso, um programa inseguro pode fornecer acesso a um invasor para assumir o controle de um servidor ou a identidade de um usuário, resultando em qualquer coisa, de uma negação de serviço para um usuário ao comprometimento de dados sigilosos, perda de serviço ou danos aos sistemas de milhares de usuários

Todo programa de computador é um alvo em potencial para um ataque de segurança. Os atacantes tentarão encontrar vulnerabilidades de segurança em suas aplicações. Eles tentarão então usar essas vulnerabilidades para roubar ou corromper programas e dados e ganhar controle de servidores e redes. Os dados de seus clientes e sua reputação estão em jogo.

A segurança não é algo que pode ser adicionado ao software!

An insecure application may require extensive redesign to secure it. You must identify the nature of the threats to your software and incorporate secure coding practices from the beginning and throughout the planning and development of your application.

Uma aplicação insegura pode exigir um redesenho extenso para protegê-la. Você deve identificar a natureza das ameaças ao seu software e incorporar práticas de programação seguras antes e durante o planejamento e desenvolvimento de sua aplicação.

Securing critical software resources is more important than ever as the focus of attackers has steadily moved toward the application layer. A 2009 SANS study found that attacks against web applications constitute more than 60% of the total attack attempts observed on the Internet.

Proteger os recursos críticos do software é mais importante do que nunca, pois o foco dos atacantes se moveu constantemente para a camada de aplicação. Um estudo de 2009, da SANS, descobriu que ataques contra aplicações web representam mais de 60% das tentativas de ataque total observadas na Internet.

O PHP é incomum, pois é uma linguagem de programação e uma estrutura da web ao mesmo tempo. Isso significa que o PHP tem muitos recursos da web incorporados a linguagem, o que torna muito fácil escrever um código inseguro.

Seguro por padrão

A complexidade mata. Isso suga a vida dos desenvolvedores, torna os produtos difíceis de planejar, desenvolver e testar, introduz desafios de segurança e causa frustração de usuários finais e administradores.

Ray Ozzie

Para que as aplicações sejam projetadas e implementadas com requisitos de segurança adequados, práticas de programação segura e um foco em riscos de segurança devem ser integrados nas operações do dia-a-dia, nos pensamentos e nos próprios processos de desenvolvimento.

Geralmente, é muito mais barato construir software seguro do que corrigir problemas de segurança após o pacote de software ter sido concluído, para não mencionar os custos que podem estar associados a uma violação de segurança.

Do jeito errado: Não desenvolvendo software seguro por padrão. Thumbs down

FAQ

É fácil interpretar de forma errada um documento escrito, então vamos esclarecer algumas coisas.

P: Qual é a intenção desse site e por que essa abordagem de confronto?

R: Para criar uma discussão e reflexão sobre as práticas atuais e visões extremas.

P: Você está dizendo que a programação orientada à objetos é ruim ou errada?

R: Não, claro que não! Nós estamos dizendo que “sempre pensar e sempre usar somente o paradigma de orientação à objetos na resolução de problemas é ruim”. Sempre que você pensa em preto e branco somente, isso é errado.

Mesmo dentro de uma única aplicação existem diferentes problemas. Multi-paradigma é, por vezes, a melhor solução, tudo depende do problema que você está tentando resolver.

Sempre que você força soluções impróprias para um problema específico, coisas ruins acontecem.

P: Você está dizendo que todos os frameworks são ruins?

R: Nós não estamos tentando julgar frameworks específicos. Estamos lidando com a questão de sempre usar um framework para trabalhar com PHP.

P: Se um framework pode me ajudar e executa rápido, por que é tão ruim?

R: Se você analisar a situação e as implicações a longo prazo e, em seguida, ver que “executar rapidamente” é o único problema que você sempre tem que lidar, não é ruim, mas então não estamos trabalhando com programação ou desenvolvimento de software, estamos lidando principalmente com soluções “apontar e clicar”.

Executar rapidamente não é projetar um software, isso significa, principalmente, que você não analisou o problema que você está enfrentando e você não ter entendeu as implicações a longo prazo de sua escolha.

P: Você está dizendo que bibliotecas de terceiros são ruins?

R: Não. Nós estamos promovendo o uso de bibliotecas de terceiros. O código que você pode facilmente integrar em seus próprios projetos sem nunca impor quaisquer limitações ou restrições. Esses são ótimos!

P: Quem é você?

R: Este site é sobre algumas ideias e sobre combater o extremismo na comunidade PHP, não é sobre a fama pessoal ou reconhecimento. Nomear pessoas só vai mudar o foco dos problemas abordados no site para as pessoas que tratam os problemas. Vamos manter o foco nas idéias.

P: Qual é a sua experiência no desenvolvimento de software?

R: As ideias, pensamentos e conclusões expressas neste site não necessitam de muita experiência para serem alcançadas, se você apenas manter o foco sobre o tema principal, que é fazer sempre uma coisa em particular porque outras pessoas dizem isso.

Leitura recomendada

PHP The Wrong Way on Hacker News

Why bad scientific code beats code following “best practices”

How to program without OOP

Coders at work - Reflections on the Craft of Programming

The traits of a proficient programmer

OWASP Secure Coding Guidelines

Security by Design Principles

Survive The Deep End: PHP Security

Refactoring Improving the Design of Existing Code

The Practice of Programming

The pragmatic programmer

Understanding programming languages

Como contribuir

Contribua no GitHub.

Adicione seções no diretório sections/LANGUAGE ou edite uma seção existente.