Ungrounded Criticism

Frequently, when someone wants to criticize some source code, we usually hear complains about hardcoded stuff.
However, most of the time, hardcode is not a real problem, and more than acceptable, sometimes it's even recommended.

Many developers completely misunderstand the hardcode problem, and make parametrized configurations of almost everything they can think of, and your program ends up as a bunch of unreadable code, completely driven by configurations that are rarely (if ever) changed. It's not uncommon to see people who put all business rules into the database, and the program itself is just a interpreter which reads those rules - your database acts as a sourcecode, and your program acts as an interpreter (back into scripting days!) - completely nonsense.

I won't discuss the definition of hardcode because it can be quite controversial. For this article you can consider that "hardcode" is when your data/rules are inside your sourcecode, and "parametrization" when they are outside your sourcecode.

So the main question is: What things can be hardcoded?

It's pretty obvious that you should not hardcode things like database connection strings, or destination email addresses. But what makes those things different than acceptable hardcoded rules/data? To answer that question, you should first ask: Why avoid hardcode at all?

The answer to this question relies on software engineering. Not on code beauty, but on finances and on your development efforts:You should make parametrizations if it saves your money.

When you make something hardcoded, you spend X efforts, but in case you need to change it in the future you will spend W efforts.
When you make something parametrized, you spend additional efforts (X+Y), but in case you need to change it in the future you will spend less efforts (W-Z).
It's a tradeoff: X is a little cheaper than X+Y during development phase, but if you need a change, maintainance W can be much more expensive than W-Z.
It's exactly like refactoring: it costs you money, but you have a payback soon, because it makes your code more maintanable.

So which alternative will save your money? It depends on expected costs.

Expected Costs

Suppose you are throwing a dice, paying 2 USD for each throw, and winning 10 USD if you get a number one on dice. Should you play this game?
Expected prize is (1/6) * 10 USD = 1,66 USD. If you are paying 2 USD and you expect to win 1,66 USD, then you are loosing money.

It's similar to PMBOK Risk Management formula: Risk Score = (Risk Probability) * (Risk Impact)

It works exactly the same in software engineering.

Back into Hardcoded

So should you have the additional effort Y of making something parametrizable? Depends on how much effort you expect to save in future maintainance.
If you expect a probability of change of P (in %), then the expected effort saving is P*(Z-W). If Y < P*(Z-W), you should make it parametrizable.
In other words, having something hardcoded costs you X in development, and an expected cost of change of P*Z. By making the same thing parametrizable, it will cost you X+Y in development, and P*(Z-W) in maintainance.

So the rule is: If parametrization efforts are cheaper than the expected saving in change efforts, parametrization should be done.

A few derived rules

We can conclude a few derived rules:

1) If something is very unlikely to be be changed in the future, probably you shouldn't make it parametrizable.(I have seen it uncountable times)
Eg: Your ecommerce system applies taxes after discounts, but you have parametrized it so that if someday Federal Law changes, you'll be able to apply taxes before discounts. How likely will it happen? Then why bother parametrizing?

2) If change efforts are insignificant, probably you shouldn't make it parametrizable
Eg: You are developing a proof-of-concept, which will run only in your machine, will be compiled only by you, and will probably be trash in a few weeks. Why bother having parametrized DAL Factories for your database? I'm pretty sure that's not what you are testing in your proof-of-concept, right?

3) If change efforts are cheaper than parametrization efforts, probably you shouldn't make it parametrizable
Eg: ASP3 is not compiled, so changing sourcecode is trivial. Why would you bother parametrizing it in a structured XML file or Database when you can just have parametrizations as constant variables inside an INCLUDE.ASP file ?

4) If change efforts are similar with either parametrization or hardcode,parametrization can be esthetic, but it's not really helpful.
Eg: Suppose you have a Build Server, completely configured with your Development, Test, Staging and Productions servers. Suppose you change sourcecode, click some buttons, and environments are updated. Why would you bother putting things into XML config files when changing XML file is as easy as changing directly source code? Use configuration wisely, but don't be afraid to leave things inside your source code.

5) If data/rule "A" cannot be parametrizable (so it's in sourcecode) and data/rule "B" cannot be changed without changing "A", you should not make "B" parametrizable either.
Eg: If you have a workflow system, why would you define all your possible states inside a XML configuration file, if transition rules cannot be parametrized (at least not easily) in XML and therefore should reside in source code? In case you need to add a new state in XML, you would also have to program new rules in source code, so that's double work to do.

Change Efforts Fixed Costs

Changing software usually involve fixed costs: where is source code? is it really the latest version? how to compile it? how to test it?
These costs vary from company to company, since each one has it's own level of self-organization maturity, but as a general rule you should note that legacy software usually tends to be more obscure and will take you long time to understand/change/build.

Parametrization Costs

Having read previous parts, now I can tell you: parametrizing data is usually cheap, and parametrizing rules is usually expensive.
As a general rule, you can parametrize your data without fear, but you should really think carefully before parametrizing rules.
Remember also that rules can rarely (if ever) be changed only by changing configuration - usually you'll need to change source code (see derived rule #5, above)

Additionally, you should note that having too many unecessary parametrizations can make your software confusing and unmaintainable.

Parametrization Guideliness

1) Web.Configs (and App.configs) are just for that. You don't have to reinvent the square wheel. You can put connection strings there without fear: those files are exactly for this.

2) Serialization can be a pain in the ass. Keep your parametrizations as simple as possible, don't try to make complex serialization rules, or use complex design patterns, in something that should be rather simple.


Suppose you have an application which sends periodic emails to Bill from the accounting department. You can hardcode "bill@yourcompany.com" into your program, or you can put it into some configuration file (or database) and name it as "AccountantEmail". Hardcoding would take you 1 minute. Putting into configuration file would take no more than 1 additional minute.
It's tempting to think of it as being a quite huge additional 100% effort, or as being a quite small effort (1 minute), but that's not the correct way of thinking - you should think in terms of payback.

Let's analyse the estimated effort.

Suppose that your company has merged with another one, and Bill is not your main accountant now. By the moment someone's need to change this rule/data, two things may happen:

1) The guy who will change this destination email address does not know anything about the system you have designed/developed.
He barely knows where the system resides. He will have to find out where are your sources, try to find where in source code is that email address, and proceed with the change.
He may not even have the appropriate IDE to recompile your application. He may not be able to recompile (where are the dll references?), or may be unsure about how to recompile it.
Let's suppose that no tests are necessary, and let's ignore the fact that after changing and recompiling a change request should be prepared (since in both cases he does not have access to production environment).
Taking all that real word facts into account, in the best case this guy will took 20 minutes to get code, change, recompile, and put into production.

2) The guy who will change this destination email address does now know anything about the system you have designed/developed.
He just asks for a copy of application's configuration file, finds out that there is a tag called "AccountantEmail" pointing to Bill's email address, and changes this tag.
In worst case, that would take 10 minutes.

Suppose now that your system has an expected life of 3 years, and during this lifetime you estimate that there is a 50% probability of changing this rule/data (destination email address) at least once.
By making the rule hardcoded during development phase would take you 1 minute, and there is a 50% chance of needing to change it (which would 20 minutes), so inicial efforts and estimated change efforts are 1 minute + 50% * 20 minutes = 11 minutes total.
By making the rule parametrized during development phase would take you 2 minutes, and there is a 50% chance of needing to change it (which would take 10 minutes), so initial efforts and estimated change efforts are 2 minutes + 50% * 10 minutes = 7 minutes total.

Therefore, this email address should be parametrized.

It's unbelievable, but Excel has this bizarre bug (documented and assumed here) that makes Calculated Fields in a Pivot Table useless.

Suppose you have a table with columns PRICE (unit price) and QTY (quantity sold). When you create a Calculated Field with the formula PRICE * QTY, and let it to use the default aggregation (SUM), you expect that they do SUM(PRICE*QTY). But what they really do is SUM(PRICE)*SUM(QTY).

In other words, if you sold 2 units at 10 USD each, and 3 units at 20 USD each, you expect that the Calculated Field sums (2*10)+(3*20)=80USD. But what it does is (2+3)*(10+20)=150USD.



Removing comments from SQL scripts is not a simple task, because there are line comments, block comments, those can be mixed with literals (strings), and to make everything harder: you can have nested block comments.

I just gave my answer to that problem here, and would like to share with you:

This removes all SQL comments, using plain regular expressons. It removes both line comments (even when there is not a linebreak after) and block comments (even if there are nested block comments). This function can also replace literals (useful if you are searching for something inside SQL procedures but you want to ignore strings).

My code was based on this answer (which is about C# comments), so I had to make a few changes:

1) Change line comments from "//" to "--"
2) Rewrite the block comments regex using balancing groups because SQL allows nested block comments, while C# doesn't.

Also, I have this "preservePositions" argument, which instead of stripping out the comments it just overwrites comments with whitespace. That's useful if you want to preserve the original position of each SQL command, in case you need to manipulate the original script while preserving original comments.

Here follows my code. If you have any doubts or problems, let me know (and I'm available for freelance on Application Lifecycle Management).

Regex everythingExceptNewLines = new Regex("[^\r\n|\r|\n]");
public string RemoveComments(string input, bool preservePositions, bool removeLiterals=false)
     //based on http://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689
     var lineComments = @"--(.*?)\r?\n";
     var lineCommentsOnLastLine = @"--(.*?)$"; // because it's possible that there's no \r\n after the last line comment
     // literals ('literals'), bracketedIdentifiers ([object]) and quotedIdentifiers ("object"), they follow the same structure:
     // there's the start character, any consecutive pairs of closing characters are considered part of the literal/identifier, and then comes the closing character
     var literals = @"('(('')|[^'])*')+"; // 'John', 'O''malley''s', etc
     var bracketedIdentifiers = @"\[((\]\])|[^\]])* \]"; // [object], [ % object]] ], etc
     var quotedIdentifiers = @"(\""((\""\"")|[^""])*\"")+"; // "object", "object[]", etc - when QUOTED_IDENTIFIER is set to ON, they are identifiers, else they are literals
     //var blockComments = @"/\*(.*?)\*/";  //the original code was for C#, but Microsoft SQL allows a nested block comments // //https://msdn.microsoft.com/en-us/library/ms178623.aspx

     //so we should use balancing groups // http://weblogs.asp.net/whaggard/377025
     var nestedBlockComments = @"/\*
                                 /\*  (?<LEVEL>)      # On opening push level
                                 \*/ (?<-LEVEL>)     # On closing pop level
                                 (?! /\* | \*/ ) . # Match any char unless the opening and closing strings   
                                 )+                         # /* or */ in the lookahead string
                                 (?(LEVEL)(?!))             # If level exists then fail

     string noComments = Regex.Replace(input,
         nestedBlockComments + "|" + lineComments + "|" + lineCommentsOnLastLine + "|" + literals + "|" + bracketedIdentifiers + "|" + quotedIdentifiers,
         me => {
             if (me.Value.StartsWith("/*") && preservePositions)
                 return everythingExceptNewLines.Replace(me.Value, " "); // preserve positions and keep line-breaks // return new string(' ', me.Value.Length);
             else if (me.Value.StartsWith("/*") && !preservePositions)
                 return "";
             else if (me.Value.StartsWith("--") && preservePositions)
                 return everythingExceptNewLines.Replace(me.Value, " "); // preserve positions and keep line-breaks
             else if (me.Value.StartsWith("--") && !preservePositions)
                 return everythingExceptNewLines.Replace(me.Value, ""); // preserve only line-breaks // Environment.NewLine;
             else if (me.Value.StartsWith("[") || me.Value.StartsWith("\""))
                 return me.Value; // do not remove object identifiers ever
             else if (!removeLiterals) // Keep the literal strings
                 return me.Value;
             else if (removeLiterals && preservePositions) // remove literals, but preserving positions and line-breaks
                 var literalWithLineBreaks = everythingExceptNewLines.Replace(me.Value, " ");
                 return "'" + literalWithLineBreaks.Substring(1, literalWithLineBreaks.Length - 2) + "'";
             else if (removeLiterals && !preservePositions) // wrap completely all literals
                 return "''";
                 throw new NotImplementedException();
         RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
     return noComments;

Quick test:

var sql = @"select /* block comment */ top 1 'a' /* block comment /* nested block comment */*/ from  sys.tables --LineComment
select top 1 '/* literal with */-- lots of comments symbols' from sys.tables --FinalLineComment"
sql = @"create table [/*] /* 
  -- huh? */
     --"" integer identity, -- /*
    [*/] varchar(20) /* -- */
         default '*/ /* -- */' /* /* /* */ */ */

Original code:

[select /* block comment */ top 1 'a' /* block comment /* nested block comment */*/ from  sys.tables --LineComment
select top 1 '/* literal with */-- lots of comments symbols' from sys.tables --FinalLineComment]
[create table [/*] /* 
  -- huh? */
     --" integer identity, -- /*
    [*/] varchar(20) /* -- */
         default '*/ /* -- */' /* /* /* */ */ */
RemoveComments(sql, true) // Filling comments with whitespace
[select                     top 1 'a'                                               from  sys.tables              
select top 1 '/* literal with */-- lots of comments symbols' from sys.tables                   ]
[create table [/*]    

     --" integer identity,      
    [*/] varchar(20)         
         default '*/ /* -- */'                  

RemoveComments(sql, true, true) //Filling comments and literals with whitespace

[select                     top 1 ' '                                               from  sys.tables              
select top 1 '                                             ' from sys.tables                   ]
[create table [/*]    

     --" integer identity,      
    [*/] varchar(20)         
         default '           '                  

Microsoft also has a parser included in SQL Server 2012 Feature Pack (just need to download SQLDom.msi). After installing this msi you just need to add a reference to C:\Program Files (x86)\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.TransactSql.ScriptDom.dll and you can start parsing (and possibly removing comments) like described here.
However, this parser is very complex, and consequently very slow. If you only need to extract/remove comments, a Regex is a much faster solution. And also doesn't depend on that external assembly. I have compared my regex to Microsoft's parser using more than 3 thousand very large SQL scripts, and I achieved the exact same results (identical byte to byte), but hundreds of times faster.

If you need a contractor/freelancer for automation tasks on ALM/SQL/deployment, get in contact.


Uma dica para fazer o seu Smartphone valer R$ 2.000 a mais:

Cadastre-se no Bike Sampa, aquele programa das Prefeitura junto com o Banco Itaú que oferece o empréstimo/aluguel de bicicletas em vários pontos da cidade.

Você se cadastra no site, põe seu celular, põe cartão de crédito, escolhe um usuário e senha. Mas na hora de alugar a bicicleta, NÃO, não precisa usar a senha que você escolheu. Basta ligar para o serviço, digitar o número da estação que você está, e a bicicleta é liberada sem nenhuma checagem se de fato o celular está com você ou com o ladrão.

Se o ladrão roubar um celular que está cadastrado no sistema, e por exemplo a pessoa cadastrou dois passes (como eu fiz, um para mim e um para minha esposa), o ladrão vai facilmente ganhar duas bicicletas com uma cestinha laranja, sem nem precisar saber a sua senha.

E você, vai ser debitado em seu cartão R$ 1.000 por cada bicicleta que for retirada e não for devolvida.

Ou seja, meu celular passou a valer R$ 2.000 a mais !! Obrigado Itaú, e Prefeitura de São Paulo. Vocês precisam realmente aprender um pouco sobre SEGURANÇA da informação.

E para dar meus dois centavos, quero lembrá-los de um dos princípios básicos da segurança informação, o Two-factor Authentication. A idéia é simples: para se autenticar você precisará de algo que você TENHA (um celular, um token, etc), e de algo que você SAIBA. No caso do Bike Sampa, basta algo que você TENHA (o celular) e eles já te liberam bicicletas, quando o correto era também pedirem uma SENHA (algo que você SAIBA).

Sabendo que o custo por cada bicicleta extraviada é de R$ 1.000, eu me pergunto se realmente isso é uma FALHA de projeto ou se é algo INTENCIONAL pra arrecadarem um dinheirinho.

E fica a dica aos ladrões: ao roubarem um smartphone, não precisa nem procurar o aplicativo. Basta ligar para o Bike Sampa, e dar umas pedaladas por minha conta !!


Um amigo meu postou o seguinte vídeo no Facebook:


No vídeo o Lair Ribeiro começa explicando o que é pH, depois começa a defender (como se fossem coisas comprovadas) que um pH alcalino é garantia de uma vida saudável e longa, e que o que faz as pessoas envelhecerem é o pH ácido. Ele vai explicando que refrigerantes fazem mal pois são ácidos, que alimentação ácida faz o seu sangue ficar ácido, que água é o único remédio para equilibrar o pH do corpo, e depois começa a falar que nem toda água é igual, que há águas que fazem bem e águas que fazem mal, por fim sugerindo que as pessoas devem tomar uma tal de "ÁGUA HEXAGONAL" que teoricamente não só o pH ideal mas também teria propriedades anti-oxidantes.

A primeira coisa curiosa é analisar a técnica de oratória.

  • O apresentador explica meia dúzia de conceitos que todo mundo conhece (como a definição pH) pra ir ganhando confiança do público, que passa a se envolver no desenvolvimento da teoria, pois no começo do discurso todos conceitos são bem leigos, então todos conseguem acompanhar.
  • Depois ele lança meia duzia de frases sensacionalistas pra causar impacto, apela para o emocional falando sobre a saúde dos "filhos que tomam veneno", "dos pais que não gostam dos filhos", etc.
  • Mais pra frente ele usa alguns termos em inglês (que quem entende inglês consegue imaginar do que se trata) para o público achar que ele realmente é expert no assunto e que entende mais do que o público.
  • Ele começa a dar entonações no discurso pra deixar as pessoas mais e mais envolvidas, como naquela parte em que ele fica explicando que o pH é uma escala logarítmica.
  • Ele lança algumas hipóteses como se fossem verdades (como a questão do câncer)
  • Por fim ele começa a tirar conclusões sem pé nem cabeça (ou seja, uma falácia), como a história de que o alimento altera o pH do corpo.

Expliquei ao meu amigo que tratava-se de um vídeo sensacionalista feito por um charlatão, e expliquei um pouco sobre como ele usou a oratória para envolver e enganar a platéia. No entanto, meu amigo insistia que a teoria do Dr. Lair Ribeiro fazia muito sentido.

Fui pesquisar pra entender melhor, olhei opinião de diversos médicos, biólogos e estudantes discutindo as teorias apresentadas no vídeo, e logo comecei a encontrar diversos links desmentindo a teoria.

Não vou entrar na discussão da biologia, pois não estudo biologia há mais de 13 anos, mas o que encontrei na minha pesquisa:

  • Existem muitas hipóteses relacionando a saúde com o pH do corpo, mas nada nunca foi provado
    (por isso que são hipóteses, e não Teorias ou Leis que são bem mais consistentes, pois exigem provas ou um escopo mais abrangente ). Ou seja, a hipótese é essencialmente um "palpite", enquanto uma teoria é uma explicação mais abrangente que junta várias linhas de evidência, alegações e modelos.
  • Quem pesquisar um pouco vai achar gente dizendo que todas doenças (até o câncer) se devem ao pH.
    (Em alguns destes sites você encontrará também muito misticismo, viagens pra quinta dimensão, gnomos, teoria da conspiração, sites que vendem produtos, etc etc)
  • Quem pesquisar um pouco também vai encontrar muita gente dizendo que o pH não muda por causa da alimentação (apenas por outros desequilibrios), e que qualquer desequilibrio alimentar (ex: excesso de acidez) é compensado pelos rins e eliminado na urina.
    (pra mim me pareceram ser sites bem mais sérios, e que não vendiam nenhum tipo de misticismo).
  • Se for ver o discurso dos fabricantes de "água alcalina", eles dizem que todos os males do mundo vem do pH ácido.
    Ex: http://www.ciacristal.com/blog/conteudo.php?ctdo=2
  • Se for ver o discurso do fabricante de refrigerante, vai ver eles desmentindo tudo.
    Ex: http://www.coca-colacompany.com/contact-us/coca-cola-rumors-facts
    Ex: http://www.rebic.com.br/boatos-e-mitos/a-acidez-dos-refrigerantes-causa-problemas-em-ossos-e-dentes/
  • Ou seja, tem que procurar fontes IMPARCIAIS. Segundo a Wikipedia http://en.wikipedia.org/wiki/Coca-Cola:
    "A crítica comum da Coca-cola de que sua acidez tem níveis alegadamente tóxicos foi provada por pesquisadores como algo sem fundamentos, e por isso vários processos foram fechados nos tribunais americanos".

A verdade é que tem muita gente desmentindo essa teoria da Dieta Ácida/Alcalina:

Na minha opinião, a medicina tem muitas hipóteses (ou seja, não provadas), poucas certezas, e ainda vai amadurecer muito.

Ainda na minha opinião, o Lair Ribeiro é um belo charlatão que vende até gelo pra esquimó: http://www.lairribeiro.com.br/produtos/

Como a maioria de nós é biólogo nem médico, é muito fácil ouvir meia duzia de argumentos que parecem bem embasados e acreditar. E é aí que entra minha crítica sobre a oratória e sobre as falácias.

Pra exemplificar como ele é usa argumentos tendenciosos, vou falar sobre a "escala logaritmica":

  • O pH=5 realmente tem 10x mais cátions H+ do que o pH=6.
  • Mas o pH=8 também tem 10x mais ânions OH- do que o pH=7.
  • Ou seja, a ordem de magnitude cresce logaritmicamente para os dois lados.
  • Então se o pH ideal é 7 (por exemplo), estar em 6 é "10x mais ácido do que deveria", mas estar em 8 também é "10x mais alcalino do que deveria".
  • No entanto o orador só reforça "o rápido crescimento" para ácido, como se para o alcalino a escala também não crescesse de forma logarítmica.

Por fim, resolvi pesquisar na Wikipedia sobre a tal Teoria da Dieta Ácida ou Alcalina, que propõe que devemos evitar alimentos e bebidas ácidos.

Segundo http://en.wikipedia.org/wiki/Acid_alkaline_diet, "faltam evidências significantes para comprovar a teoria".
Segundo http://en.wikipedia.org/wiki/Alkaline_diet "as alegações não tem evidência médica e usam premissas contrárias ao atual entendimento da fisiologia humana". O mesmo artigo também diz que a hipótese que correlacionava dieta ácida com osteoporose ultimamente está sendo descartada.

( É óbvio que aqueles que querem vender placebo tentam desmerecer a Wikipedia, chamando ela de "cética", etc: http://www.lifeionizers.com/blog/alkaline-water/alkaline-water-wikipedia/ )

Então eu resolvi pesquisar sobre a tal "Água Hexagonal" que o Lair Ribeiro está promovendo (que me parece que é vendida no Brasil com o nome deAcquaLive):

Segundo http://en.wikipedia.org/wiki/Hexagonal_water:

"Hexagonal water is a term used in a marketing scam[1][2] that claims the ability to create a certain configuration of water that is better for the body.[3] The term "hexagonal water" refers to a cluster of water forming a hexagonal shape that supposedly enhances nutrient absorption, removes metabolic wastes, and enhances cellular communication, among other things.[4] Similar to the dihydrogen monoxide hoax, the scam takes advantage of the consumer's limited knowledge of chemistry, physics, and physiology."

Ou seja, ela foi descrita como um "golpe de marketing que alega a possibilidade de criar uma disposição da água que seria melhor para o corpo":

A última frase mostra exatamente o que eu falei sobre como é fácil enganar os leigos: "O golpe se utiliza do conhecimento limitado que o consumidor tem sobre química, física e fisiologia". Basta um charlatão que domina a técnica da oratória, que ele consegue demonstrar uma conclusão errada (uma falácia) para os leigos acreditarem e comprarem placebo.

Mais sobre a pseudociência da água hexagonal: http://www.chem1.com/CQ/clusqk.html

Recapitulando, os americanos inventaram um golpe, que provavelmente deve ser muito rentável, os brasileiros copiaram a idéia e contrataram o Dr. Lair Ribeiro para ser o garoto propaganda da nova água que resolve todos os problemas de saúde, rejuvenesce, previne o câncer e a osteoporose.

O que me chateia mais não são os charlatões, nem o uso do marketing e da oratória para enganar o consumidor, mas sim as pessoas que não tem discernimento para entender os golpes e pesquisar a verdade. Apesar de ter formação em exatas (que envolve muita lógica), já fiz curso de oratória, além de várias disciplinas de marketing, e me assusta ver como somos tão facilmente manipulados com pseudociência, falácias (conclusões feitas de maneira ilógica ou sem fundamento), e outras técnicas de persuasão.

O maior problema da falta de discernimento não é que somos manipulados há décadas como consumidores, mas sim que somos manipulados há séculos por governantes, imprensa, e líderes religiosos.

Veja bem, eu não estou dizendo que refrigerante é bom, e eu próprio os evito. O que estou dizendo é que não dá pra acreditar em pseudociência e transformar isso em histeria coletiva, como o pessoal faz no facebook. A pseudociência é igual ao Notícias Populares: só sobrevive através de gente que não questiona a informação que lê.

Já falei demais. Vou tomar uma água hexagonal pra recompor minhas energias...