tag:blogger.com,1999:blog-44113176045833282792024-03-24T16:31:50.692-07:00Hiper CódigoBlog sobre programação usando php, codeigniter, javascript e outras tecnologias. De vez em quando devem aparecer outros temas não focados em tecnologia.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.comBlogger93125tag:blogger.com,1999:blog-4411317604583328279.post-45314500762653041222013-09-30T17:37:00.002-07:002013-09-30T17:37:40.306-07:00Criando Ranks no Postgres usando Window FunctionsVamos supor que você tenha a seguinte tabela:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggarQEe4-jHH-aQzAqY-m2ZTsWXrQz3ndS8WiYoCbIeXQJDLFJgbl-wvpByYevGpxGr4BYXXiyPxlhJccDJfMvIcURVzi_wp2kfFHRSHurbA5H7Z0OUAoAPhfPNIvjhm0nWWp0hFLXZi0/s1600/table.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggarQEe4-jHH-aQzAqY-m2ZTsWXrQz3ndS8WiYoCbIeXQJDLFJgbl-wvpByYevGpxGr4BYXXiyPxlhJccDJfMvIcURVzi_wp2kfFHRSHurbA5H7Z0OUAoAPhfPNIvjhm0nWWp0hFLXZi0/s400/table.png" width="400" /></a></div>
<br />
E você tenha que ordená-la de acordo com os seguintes critérios: a maior média por departamento, seguido de maior nota a, maior nota b e finalmente maior nota c. Fica bem simples se usarmos a cláusula order by:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">SELECT department, name, grade_a, grade_b, grade_c</span><br />
<span style="font-family: Courier New, Courier, monospace;">FROM candidates</span><br />
<span style="font-family: Courier New, Courier, monospace;">ORDER BY department, ((grade_a + grade_b + grade_c) / 3) DESC,</span><br />
<span style="font-family: Courier New, Courier, monospace;">grade_a DESC, grade_b DESC, grade_c DESC</span><br />
<br />
<br />
Resultado:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBnrmmpixI5fGuWJ35Au82ydXYzVt1iYlCBTV9dXhyu3IW5ZGVqIp_Y9oJG-srIp0YLC9yV5PYDzWEMbAAomKwLPXVF6GnI2Hvp-1oRG7mUSARheJjH3KNuT_7Ee2D02hGzLCFZ_VAgow/s1600/table_order_by.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBnrmmpixI5fGuWJ35Au82ydXYzVt1iYlCBTV9dXhyu3IW5ZGVqIp_Y9oJG-srIp0YLC9yV5PYDzWEMbAAomKwLPXVF6GnI2Hvp-1oRG7mUSARheJjH3KNuT_7Ee2D02hGzLCFZ_VAgow/s400/table_order_by.png" width="400" /></a></div>
<br />
<br />
Mas agora queremos criar uma qualificação indicando a posição do candidato de acordo com os critérios acima e esta posição deve ser relativa ao departamento que ele pertence, ou seja queremos saber os trê melhores qualificados no departamento "Development" e os três melhores no departamento "Marketing". Talvez muitos já estejam pensando em usar sua linguagem de programação favorita para resolver este problema mas no Postgres temos as <a href="http://www.postgresql.org/docs/8.4/static/tutorial-window.html">Window Functions</a>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">SELECT department, name, grade_a, grade_b, grade_c,</span><br />
<span style="font-family: Courier New, Courier, monospace;">rank() OVER(PARTITION BY department ORDER BY ((grade_a + grade_b + grade_c) / 3) DESC, grade_a DESC, grade_b DESC, grade_c DESC)</span><br />
<span style="font-family: Courier New, Courier, monospace;">FROM candidates</span><br />
<br />
<br />
Resultado:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuzaRtHtF9DjmeMbw_fkzF6vQbBlmLGMuVgWKnhg80BrrNGTI2gKO95IxRfokQcubiEr9ZSVQD1Png7fb2L0pBAIPQ91nmv1JB-bV3RI1I2KC5IjeMRxLnTcsMKujFFpPK0G0CdNjtw80/s1600/table_ranked.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="118" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuzaRtHtF9DjmeMbw_fkzF6vQbBlmLGMuVgWKnhg80BrrNGTI2gKO95IxRfokQcubiEr9ZSVQD1Png7fb2L0pBAIPQ91nmv1JB-bV3RI1I2KC5IjeMRxLnTcsMKujFFpPK0G0CdNjtw80/s400/table_ranked.png" width="400" /></a></div>
<br />
Legal, agora temos um número indicando a posição de cada candidato relativo ao seu departamento. Mas digamos agora que apenas os dois melhores candidatos de cada departamento devem ser retornados. Neste caso a seguinte query deve ser satisfatória:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">SELECT *</span><br />
<span style="font-family: Courier New, Courier, monospace;">FROM</span><br />
<span style="font-family: Courier New, Courier, monospace;">(SELECT department, name, grade_a, grade_b, grade_c,</span><br />
<span style="font-family: Courier New, Courier, monospace;">rank() OVER(PARTITION BY department ORDER BY ((grade_a + grade_b + grade_c) / 3) DESC, grade_a DESC, grade_b DESC, grade_c DESC)</span><br />
<span style="font-family: Courier New, Courier, monospace;">FROM candidates) AS sub_query</span><br />
<span style="font-family: Courier New, Courier, monospace;">WHERE rank < 3</span><br />
<br />
<br />
Resultado:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimapTwCB_IWJtZVWCS-IVwzvPnAz-vARWUuUFowKmJ7CGJWfPGOB3A3hEzPivJfHWcT0_IKGZiq9cwQ4NDqcEPSoBjgphHjW34oWDiBHfyqHrhS3khwNyvgaXlQ_1i7xpH_zncVBdvato/s1600/table_ranked_filtered.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimapTwCB_IWJtZVWCS-IVwzvPnAz-vARWUuUFowKmJ7CGJWfPGOB3A3hEzPivJfHWcT0_IKGZiq9cwQ4NDqcEPSoBjgphHjW34oWDiBHfyqHrhS3khwNyvgaXlQ_1i7xpH_zncVBdvato/s400/table_ranked_filtered.png" width="400" /></a></div>
<br />
Espero que estes exemplos possam te ajudar a entender como as Window Functions funcionam e como elas podem te ajudar.<br />
<br />
Referência:<a href="http://postgresguide.com/tips/window.html">http://postgresguide.com/tips/window.html</a>Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com2tag:blogger.com,1999:blog-4411317604583328279.post-87232190969183943902013-08-31T17:01:00.001-07:002013-09-30T17:38:08.388-07:00GROUP_CONCAT no PostgresO MySQL tem uma função muito legal chamada <a href="https://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html#function_group-concat">GROUP_CONCAT</a>. Ela concatena os valores de uma coluna em uma string separados por um separador que por padrão é uma vírgula(,). Para exemplificar considere a seguinte estrutura no banco de dados(pode ser usada tanto no MySQL quanto no Postgres):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">create table countries_languages(</span><br />
<span style="font-family: Courier New, Courier, monospace;">country_code varchar(4) not null,</span><br />
<span style="font-family: Courier New, Courier, monospace;">language varchar(32) not null,</span><br />
<span style="font-family: Courier New, Courier, monospace;">primary key(country_code, language)</span><br />
<span style="font-family: Courier New, Courier, monospace;">);</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">insert into countries_languages(country_code, language) values('BR', 'Portuguese');</span><br />
<span style="font-family: Courier New, Courier, monospace;">insert into countries_languages(country_code, language) values('THA', 'Chinese');</span><br />
<span style="font-family: Courier New, Courier, monospace;">insert into countries_languages(country_code, language) values('THA', 'Khmer');</span><br />
<span style="font-family: Courier New, Courier, monospace;">insert into countries_languages(country_code, language) values('THA', 'Kuy');</span><br />
<span style="font-family: Courier New, Courier, monospace;">insert into countries_languages(country_code, language) values('THA', 'Lao');</span><br />
<br />
<br />
Ao executarmos a seguinte consulta:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">select country_code, language as languages</span><br />
<span style="font-family: Courier New, Courier, monospace;">from countries_languages</span><br />
<span style="font-family: Courier New, Courier, monospace;">where country_code = 'THA'</span><br />
<br />
<br />
Obteremos a seguinte saída:<br />
<table border="1" cellspaci0g="0" cols="2" frame="VOID" rules="NONE">
<colgroup><col width="38"></col><col width="60"></col></colgroup>
<tbody>
<tr>
<td align="LEFT" height="17" width="38">THA</td>
<td align="LEFT" width="60">Chinese</td>
</tr>
<tr>
<td align="LEFT" height="17">THA</td>
<td align="LEFT">Khmer</td>
</tr>
<tr>
<td align="LEFT" height="17">THA</td>
<td align="LEFT">Kuy</td>
</tr>
<tr>
<td align="LEFT" height="17">THA</td>
<td align="LEFT">Lao</td>
</tr>
</tbody>
</table>
<br />
Usando o GROUP_CONCAT nesta outra consulta:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">select country_code, GROUP_CONCAT(language) as languages</span><br />
<span style="font-family: Courier New, Courier, monospace;">from countries_languages</span><br />
<span style="font-family: Courier New, Courier, monospace;">where country_code = 'THA'</span><br />
<span style="font-family: Courier New, Courier, monospace;">GROUP BY country_code</span><br />
<br />
<br />
A saída será:<br />
<table border="0" cellspacing="0" cols="2" frame="VOID" rules="NONE">
<colgroup><col width="38"></col><col width="157"></col></colgroup>
<tbody>
<tr>
<td align="LEFT" height="17" width="38">THA</td>
<td align="LEFT" width="157">Chinese,Khmer,Kuy,Lao</td>
</tr>
</tbody>
</table>
<br />
<br />
Certo! Bem legal e útil quando quisermos exportar dados ou apresentá-los, mas como podemos fazer isso no banco de dados Postgres?<br />
<br />
No Postgres não existe a função GROUP_CONCAT mas nele temos <a href="http://www.postgresql.org/docs/current/static/arrays.html">arrays</a>. Uma forma de ter a mesma saída que o MySQL usando arrays em Postgres é:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">select country_code, array_to_string(array(SELECT language FROM countries_languages WHERE country_code = 'THA'), ',')</span><br />
<span style="font-family: Courier New, Courier, monospace;">from countries_languages</span><br />
<span style="font-family: Courier New, Courier, monospace;">where country_code = 'THA'</span><br />
<span style="font-family: Courier New, Courier, monospace;">GROUP BY country_code</span><br />
<br />
<br />
O resultado da sub-consulta "SELECT language FROM countries_languages WHERE country_code = 'THA'" é convertido para um array que por sua vez é convertido para uma string pela função <a href="http://www.postgresql.org/docs/current/static/functions-array.html">array_to_string</a> com cada valor do array separado por uma vírgula. É mais verboso e exige uma sub-query mas o resultado é o mesmo.<br />
<br />
Referência:<a href="http://stackoverflow.com/a/4469002">http://stackoverflow.com/a/4469002</a>Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-17730880753022391292013-07-31T16:34:00.001-07:002013-07-31T16:34:43.592-07:00Truques SQL<h2>
Inserindo a partir de uma consulta SQL</h2>
<div>
Supondo que temos a seguinte estrutura de tabelas:</div>
<div>
CREATE TABLE users(</div>
<div>
id int not null,</div>
<div>
name text not null,</div>
<div>
email text</div>
<div>
);</div>
<div>
<br /></div>
<div>
<div>
CREATE TABLE user_searches_results(</div>
<div>
id int not null,</div>
<div>
id_user int not null,</div>
<div>
search_date date</div>
<div>
);</div>
</div>
<div>
<br /></div>
<div>
Agora como nós podemos guardar todos os id's da tabela users na tabela user_searches_results retornados na seguinte consulta: SELECT id FROM users WHERE name LIKE 'Maria%' ?</div>
<div>
Este seguinte comando sql é capaz de fazer a tarefa de forma muito eficiente:</div>
<div>
<div>
INSERT INTO user_searches_results(id, id_user, search_date)</div>
<div>
SELECT 1, id, now() FROM users WHERE name LIKE 'Maria%';</div>
</div>
<div>
Simples não?</div>
<div>
<br /></div>
<h2>
Retornando um registro aleatório a partir de uma consulta</h2>
<h4>
MySQL</h4>
<div>
SELECT column1, column2, ... FROM table ORDER BY rand() LIMIT 1</div>
<div>
<br /></div>
<h4>
PostgreSQL</h4>
<div>
SELECT column1, column2, ... FROM table ORDER BY random() LIMIT 1</div>
<div>
<br /></div>
<h4>
SQL Server</h4>
<div>
<div>
SELECT TOP 1 column1, column2, ... FROM table</div>
<div>
ORDER BY NEWID()</div>
</div>
<div>
<br /></div>
<h4>
DB2</h4>
<div>
<div>
SELECT column1, column2, RAND() as IDX </div>
<div>
FROM table </div>
<div>
ORDER BY IDX FETCH FIRST 1 ROWS ONLY</div>
</div>
<div>
<br /></div>
<h4>
Oracle</h4>
<div>
<div>
SELECT column1 FROM</div>
<div>
( SELECT column1 FROM table</div>
<div>
ORDER BY dbms_random.value )</div>
<div>
WHERE rownum = 1</div>
</div>
<div>
<br /></div>
<h2>
Selecionar o segundo maior(ou menor valor) de uma coluna</h2>
<div>
<div>
SELECT MAX(column)</div>
<div>
FROM table</div>
<div>
WHERE column < (SELECT MAX(column) FROM table )</div>
<div>
<br /></div>
</div>
<div>
Use MIN se você quiser o segundo menor valor e não se esqueça do operador >.</div>
<div>
<br /></div>
<h2>
Copiar a estrutura de uma tabela sem copiar os dados(MySQL, PostgresSQL)</h2>
<div>
CREATE TABLE users_2 AS (SELECT * FROM users WHERE 1=0);</div>
<div>
Observe que índices e constraints não são duplicados.</div>
<div>
<br /></div>
<h2>
Gerar SQL para atualizar os dados de uma tabela baseado no conteúdo de outra tabela(PostgresSQL)</h2>
<div>
Considerem a seguinte estrutura e dados:</div>
<div>
<div>
CREATE TABLE departments(</div>
<div>
id int not null,</div>
<div>
name text not null,</div>
<div>
employee_count int</div>
<div>
);</div>
<div>
<br /></div>
<div>
INSERT INTO departments values(1, 'Development', 0);</div>
<div>
INSERT INTO departments values(2, 'Sales', 0);</div>
<div>
INSERT INTO departments values(3, 'Marketing', 0);</div>
<div>
<br /></div>
<div>
CREATE TABLE employees(</div>
<div>
id int not null,</div>
<div>
id_department int not null,</div>
<div>
name text not null</div>
<div>
);</div>
<div>
<br /></div>
<div>
INSERT INTO employees VALUES(1, 2, 'Ryu');</div>
<div>
INSERT INTO employees VALUES(2, 2, 'Ken');</div>
<div>
INSERT INTO employees VALUES(3, 3, 'Chun-Li');</div>
<div>
INSERT INTO employees VALUES(4, 1, 'Guile');</div>
<div>
<br /></div>
<div>
Certo. Agora precisamos atualizar a tabela departments com o número de empregados que cada uma contém. Com o seguinte sql os comandos de update serão gerados automaticamente:</div>
<div>
SELECT 'UPDATE departments SET employee_count = ' || COUNT(e.id) </div>
<div>
<div>
|| ' WHERE id = ' || e.id_department || ';'</div>
<div>
FROM employees e</div>
<div>
GROUP BY e.id_department;</div>
</div>
</div>
<div>
<br /></div>
<div>
A linguagem SQL pode ser mais poderosa e útil do você imagina.</div>
Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com1tag:blogger.com,1999:blog-4411317604583328279.post-108483286451603522013-06-30T11:25:00.001-07:002013-06-30T11:25:40.352-07:00Locale e como isso pode afetar o retorno da função iconvExecute o trecho de código abaixo na linha de comando o observe o resultado:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">ini_set('display_errors', 1);</span><br />
<span style="font-family: Courier New, Courier, monospace;">error_reporting(E_ALL);</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">header('Content-Type: text/plain; charset=utf-8');</span><br />
<span style="font-family: Courier New, Courier, monospace;">$utf8_word = 'GOIÂNIA';</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ascii_word = iconv('UTF-8', 'US-ASCII//TRANSLIT', $utf8_word);</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo $ascii_word, "\n";</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo md5($ascii_word);</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo "\n";</span><br />
<br />
<br />
No meu sistema(PHP 5.3.6-13ubuntu3.10 with Suhosin-Patch (cli)) a saída foi:<br />
<br />
GOIANIA<br />
1d92cfdaed61eba2c8dea6e670df9f38<br />
<br />
Certo, agora executando o mesmo script através do browser e do servidor web a saída é a seguinte:<br />
<br />
GOI?NIA<br />
848aa917b7d132a581c0d9f91bc1b03f<br />
<br />
Humm... Por que o mesmo script tem saídas diferentes quando executado na linha de comando e quando executado no servidor web?<br />
<br />
Mas o que este script faz mesmo? Ele simplesmente usa a função <a href="http://br1.php.net/manual/en/function.iconv.php">iconv</a> para converter uma string codificada com UTF-8(GOIÂNIA) para codificação US-ASCII, o nosso velho conhecido ASCII, usando transliteração o que faz com que quando um caractere não possa ser representado na codificação alvo a função tenta usar um caractere da codificação alvo que seja parecido. Mas ainda não sabemos poque o script tem saídas diferentes em ambientes diferentes.<br />
<br />
Acontece que a função iconv é afetada pelo locale do ambiente, usando a função <a href="http://br2.php.net/setlocale">setlocale</a> podemos verificar qual locale está sendo usado:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$current_locale = setlocale(LC_ALL, "0");</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo "Current locale:$current_locale", "\n";</span><br />
<br />
<br />
No servidor web a resposta é "C" na linha de comando é "LC_CTYPE=pt_BR.UTF-8;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C", que é o locale configurado no meu sistema operacional. Ou seja enquando no servidor web o locale é C na linha de comando é utf-8. Então é só ajustarmos o locale antes de chamar a função iconv para que ela tenha o mesmo comportamento em qualquer ambiente.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">ini_set('display_errors', 1);</span><br />
<span style="font-family: Courier New, Courier, monospace;">error_reporting(E_ALL);</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">setlocale(LC_ALL, 'pt_BR.UTF-8');</span><br />
<span style="font-family: Courier New, Courier, monospace;">header('Content-Type: text/plain; charset=utf-8');</span><br />
<span style="font-family: Courier New, Courier, monospace;">$utf8_word = 'GOIÂNIA';</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ascii_word = iconv('UTF-8', 'US-ASCII//TRANSLIT', $utf8_word);</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo $ascii_word, "\n";</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo md5($ascii_word);</span><br />
<span style="font-family: Courier New, Courier, monospace;">echo "\n";</span><br />
<br />
<br />
Mas existem algumas considerações a serem feitas, o locale configurado através da função setlocale deve estar instalado no servidor onde o código será executado, caso contrário a função setlocale simplesmente retorna FALSE e o resultado pode ser diferente para cada ambiente quando demonstrado no início do texto. Outra consideração é que o efeito da função setlocale é "por processo". Na documentação da função existe um "warning" explicando que quando existirem vários scripts rodando em diferentes threads no servidor(algo muito comum se seu servidor tem várias requisições ao mesmo tempo) uma chamada a setlocale para mudar o locale vai afetar <b>todos </b>os scripts em execução no momento mesmo que o script em si não tenha chamado setlocale.<br />
<br />
Espero que este texto possa ajudar as pessoas pegas de surpresa pelos resultados da função iconv. Até a próxima.<br />
<br />
Referências:<br />
<a href="http://stackoverflow.com/questions/9771886/what-factors-influence-a-successful-iconv-translit-conversion">http://stackoverflow.com/questions/9771886/what-factors-influence-a-successful-iconv-translit-conversion</a><br />
Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-373275422348049052013-05-30T12:02:00.001-07:002013-05-30T12:02:13.775-07:00phpsh um REPL para PHPVocês sabem o que a sigla REPL significa? Ela significa <a href="https://en.wikipedia.org/wiki/REPL">read-eval-print-loop</a>. Ela é usada para denominar um abiente shell de programação interativa. É como um programa de linha de comando onde você pudesse executar os comandos de sua linguagem de programação favorita e observar o que cada comando faz imediatamente depois de apertar Enter. Diversas linguagens de programação possuem seus REPL's como Python, Ruby, Perl, Scala, Groovy, Forth, Lisp, Javascript etc. Aliás é bem provável que você que está lendo este texto agora já tenha um ambiente REPL para Javascript instalado e funcional, afinal, os browsers mais usados como Firefox, Chrome e Iternet Explorer possuem interpretadores Javascript. Aperte F12 no Chrome e Internet Explorer ou Ctrl + Shift + K no firefox e procure pela aba console.<br />
<br />
O PHP também já vem com um REPL instalado. Se você executar o seguinte comando:<br />
<span style="font-family: Courier New, Courier, monospace;">php -a</span><br />
Verá que ele irá abrir o "Interative Shell". Mas infelizmente ele é muito limitado, no meu caso por exemplo aparece um til(~) cada vez que aperto a tecla Delete e o <a href="http://php.net/manual/en/features.commandline.interactive.php">autoloading</a> não está disponível. E no windows eu diria que ele simplesmente não funciona.<br />
<br />
O pessoal do Facebook criou um REPL bem legal para PHP. Chamdo phpsh ele é implementado na maior parte em Python(pecado mortal!). Mas enfim, ele tem recursos legais como autoloading, opção para carregar código já existente e a tecla Delete funciona!<br />
<br />
O endereço com instruções para instalá-lo está <a href="https://github.com/facebook/phpsh">aqui</a>. Para baixá-lo eu simplesmente clonei o repositório usando o git, mas você também pode obtê-lo através de um arquivo zip na mesma página.<br />
<br />
Existem alguns módulos PHP que precisam estar instalados, são eles: <a href="http://php.net/manual/en/book.pcre.php">pcre</a>, <a href="http://php.net/manual/en/book.posix.php">posix</a> e <a href="http://php.net/manual/en/book.tokenizer.php">tokenizer</a>. No caso do Python também existem algumas dependências. No meu caso tive que instalar o easy_install para instalar o pacote readline. Para instalar o easy_install tive que instalar o pacote python-setuptools. Depois de instalar o setuptools basta usar o comando para instalar o readline:<br />
<span style="font-family: Courier New, Courier, monospace;">sudo easy_install readline</span><br />
E depois segui as instruções para instalar globalmente:<br />
<span style="font-family: Courier New, Courier, monospace;">cd phpsh (precisamos entrar no diretório raiz do phpsh depois de baixá-lo)</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">python setup.py build</span><br />
<span style="font-family: Courier New, Courier, monospace;">sudo python setup.py install</span><br />
<span style="font-family: Courier New, Courier, monospace;">phpsh</span><br />
<br />
E pronto! Você já pode escrever código PHP e apertar enter para ver o resultado. Eu particularmente acho muito úteis estes ambientes REPL. Quando eu quero ver o que uma função faz ou simplesmente testar algumas poucas linhas de código é muito fácil abrir o terminal e já começar a escrever o código e poucos momentos depois já ver o resultado. Espero que isto ajude vocês tanto quanto me ajuda.<br />
Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com1tag:blogger.com,1999:blog-4411317604583328279.post-53290464593629307052013-04-30T13:34:00.001-07:002013-04-30T13:34:55.534-07:00Estimando o valor de pi usando um quadrado, um círculo e probabilidade<br />
Existe uma técnica bem legal de se estimar o valor da constante π usando o quadrado e círculo abaixo:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPW2aO5fMHw4vcgerKwaXLgHdG8qeWuuYPDPj0wYsHHw9Y6r9ox_4XqIoTiMBc8acwa5u3pxpvSrUje9liKyPUf1nqCKwR_fHjOnM3_4fZgtArFSZyiwvf4saCZT1SkDA5GwTTs2tvL74/s1600/circle-square.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPW2aO5fMHw4vcgerKwaXLgHdG8qeWuuYPDPj0wYsHHw9Y6r9ox_4XqIoTiMBc8acwa5u3pxpvSrUje9liKyPUf1nqCKwR_fHjOnM3_4fZgtArFSZyiwvf4saCZT1SkDA5GwTTs2tvL74/s320/circle-square.png" width="320" /></a></div>
<br />
<br />
O valor do raio do círculo é 1. Assim a área do círculo é π * r ^ 2 = π * (1 * 1) = π.<br />
E a área do quadrado é :2 ^ 2 = 2 * 2 = 4. Só lembrando que estou usando o símbolo ^ para representar a <a href="http://pt.wikipedia.org/wiki/Exponencia%C3%A7%C3%A3o">exponenciação</a>.<br />
<br />
E agora nós selecionamos milhares de pontos dentro do quadrado. Para uma boa aproximação devemos fazer isso milhões de vezes. Uma vez isso feito você pode usar a seguinte fórmula para encontrar o valor de π:<br />
π/4 = número de pontos dentro do círculo / número total de pontos<br />
<br />
modificando a fórmula para encontrar o valor de π:<br />
π = (número de pontos dentro do círculo * 4) / número total de pontos<br />
<br />
Considerando-se que para obtermos um bom resultado devemos escolher milhões de pontos, seria muito demorado e entediante fazer este processo manualmente, portanto, nada melhor do que usarmos um computador para isso. E o programa em PHP abaixo faz exatamente isso:<br />
<br />
<script src="https://gist.github.com/ricardosdl/5491680.js"></script><br />
<br />
Acredito que não seja difícil entender o código. Neste exemplo selecionamos 5 milhões de pontos dentro do quadrado. A inspiração veio deste <a href="http://www.businessinsider.com/the-most-controversial-math-problems-2013-3#-45">link</a>, lá você também pode encontrar uma boa explicação de como a técnica funciona. Ou você pode usar a constante <a href="http://br2.php.net/manual/en/math.constants.php">M_PI</a> da linguagem PHP.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-22391085179725235712013-03-06T17:06:00.001-08:002013-03-06T17:06:23.805-08:00Eficiência MatemáticaVou mostrar-lhes dois trechos de código que fazem exatamente a mesma coisa:<br />
<br />
<script src="https://gist.github.com/ricardosdl/5104631.js"></script><br />
<br />
<br />
<script src="https://gist.github.com/ricardosdl/5104638.js"></script><br />
<br />
Analisem os trechos de código e tentem descobrir o que eles fazem. Uma dica: a essência de tudo está na função <b>calc</b>.<br />
<br />
<br />
Já analisou? Entendeu o que está acontecendo? Bom, estes trechos de código calculam 1 milhão de vezes a soma do intervalo de números entre 1 e um número aleatório entre 1 e 500. Ao mesmo tempo ele toma nota de quanto tempo este processo leva usando a função <a href="http://www.php.net/manual/en/function.microtime.php">microtime</a>.<br />
<br />
<br />
Você conseguiu descobrir o que estava acontecendo antes de eu ter explicado? Se você não conseguiu, não tem problema, eu vou explicar. Comparando os dois trechos de código, qual você diria que apresenta com mais clareza o comportamento que expliquei anteriormente?<br />
<br />
<br />
O primeiro trecho usa funções cujos nomes dão uma certa ideia sobre o que está acontecendo. "<a href="http://www.php.net/manual/en/function.array-sum.php">array_sum</a>" retorna a soma dos valores dentro de um array. "<a href="http://www.php.net/manual/en/function.range.php">range</a>" retorna um array preenchido com números em um intervalo que vai do primeiro parâmetro passado até o segundo parâmetro passado. Então <b>array_sum</b> soma o conteúdo de um array, <b>range</b> retorna um array de números, bingo! Tudo o que o loop faz é somar os números naturais de 1 até um intervalo superior que varia de 1 até 500. Um milhão de vezes!<br />
<br />
<br />
E o segundo trecho? Não há chamadas de funções nesta versão da função calc. Ela mais parece uma fórmula matemática. E realmente é, é a seguinte fórmula:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhABkiccu5UNbDps2HTPIXiAI4lmn0Bz3L50njqtVQqODjS-bQJ52Mcjjfk1rTIXOo8lJFBCv5pBB_g6ZN4dhQbwXJuYq2LIcTvDuCsv6rpNBRnnzUzM3itWKFFtr43HOM6JMXDoXCqags/s1600/The_sum_of_the_first_n_natural_numbers.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhABkiccu5UNbDps2HTPIXiAI4lmn0Bz3L50njqtVQqODjS-bQJ52Mcjjfk1rTIXOo8lJFBCv5pBB_g6ZN4dhQbwXJuYq2LIcTvDuCsv6rpNBRnnzUzM3itWKFFtr43HOM6JMXDoXCqags/s1600/The_sum_of_the_first_n_natural_numbers.png" /></a></div>
E ela simplesmente retorna a soma entre os números naturais de 1 até n.<br />
<br />
Certo! O que eu quero demonstrar com tudo isso? Primeiro eu convido vocês a executar os trechos de código em seus computadores e comparar o tempo gasto nos cálculos tanto pelo trecho usando array_sum quanto pelo outro usando a fórmula matemática, no meu computador um core i7 2600 3,40 GHz os tempos em segundos, cada trecho foi executado três vezes, foram os seguintes:<br />
<br />
<b>array_sum</b>:<br />
<div>
<ul>
<li>42,979010105133</li>
<li>42,527684926987</li>
<li>43,008407831192</li>
</ul>
<b>fórmula matemática</b>:</div>
<div>
<ul>
<li>9,8508331775665</li>
<li>9,889456987381</li>
<li>9,9301979541779</li>
</ul>
Não é um benchmark rigoroso ou bem feito, mas como vocês podem ver a diferença de tempo entre as duas abordagens rodando no meu computador é enorme. E acredito que aqueles que testarem o código também observarão grandes diferenças de tempo de execução dos dois trechos.</div>
<div>
<br /></div>
<div>
Eu acredito que a grande diferença de eficiência de execução se deve principalmente a dois pontos principais. A função range cria um array dinamicamente e isso envolve alocação de memória por parte do interpretador PHP, o que toma tempo. Mas é o segundo ponto que deve realmente impactar na performance, a função <b>array_sum</b> deve percorrer cada elemento do array gerado pela função <b>range</b> e laços de repetição afetam a performance significativamente.</div>
<div>
<br /></div>
<div>
Eu não tenho dúvidas de que o código usando <b>array_sum</b> é mais fácil de se ler, mais elegante e usa todo o poder do dinamismo da linguagem PHP. Mas a eficiência da abordagem matemática é inegável, e alguns até poderiam dizer que ela é tão elegante quanto a outra, sempre podemos adicionar um comentário informando o que a fórmula faz, não é? Acho que preciso voltar a estudar matemática.</div>
Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com3tag:blogger.com,1999:blog-4411317604583328279.post-84408661246921731412013-02-19T15:01:00.001-08:002013-02-19T15:01:53.979-08:00Como testar o desempenho de suas aplicações web de forma fácil e rápidaVocê acabou de finalizar os últimos retoques no seu site ou aplicação. O cliente já fez exaustivos testes além dos testes realizados por você mesmo. Tudo pronto para colocar em produção aquele código no qual você passou meses trabalhando. E de repente, quando mais de 30 usuários estão fazendo requisições ao mesmo tempo, as requisições demoram a serem respondidas. Parece que a página inicial do site não vai aparecer nunca. Clicar em "salvar" naque formulário de cadastro se torna uma bela desculpa para uma pausa para café.<br />
<br />
"Mas como isso está acontecendo?" Você se pergunta. Nos testes realizados as resquisições demoravam poucas dezenas de milisegundos. Como isso foi acontecer? Bom, provavelmente os testes foram realizados com apenas um usuário acessando o servidor, talvez dois. Com o site ou aplicação se tornando popular vários usuários vão fazer seu código ser executado em várias requisições ao <b>mesmo tempo.</b> E é neste momento que estas supresas aparecem.<br />
<br />
Para te ajudar a tentar prever como seu código vai se comportar com várias requisições simultâneas existe uma ferramenta muito útil chamada <a href="https://httpd.apache.org/docs/2.2/programs/ab.html">ab</a> (Apache Benchmark), sobre a qual já falei <a href="http://hipercodigo.blogspot.com.br/2012/09/falar-sobre-aplicacoes-com-muitas.html">aqui</a>. Em uma máquina com gerenciador de pacotes como o <a href="https://en.wikipedia.org/wiki/Advanced_Packaging_Tool">apt-get</a> instalá-la é muito fácil. Basta usar o comando:<br />
<b>#apt-get install apache2-utils</b><br />
<br />
Sua execução básica é assim:<br />
<b>$ab -c 10 -t 30 http://localhost/sitecobaia/</b><br />
<br />
Este comando vai abrir 10 conexões simultâneas e enviar requisições durante 30 segundos para o endereço indicado. Uma variação deste comando é adicionar um parâmetro para que as conexões sejam do tipo <a href="https://en.wikipedia.org/wiki/HTTP_persistent_connection">keep-alive</a>(comum nas as requisições enviadas por navegadores).<br />
<b>$ab -kc 10 -t 30 http://localhost/sitecobaia/</b><br />
<br />
Quanto aos números você é livre para alterá-los como quiser. Se você for realmente sádico coloque algo como 100 requisições simultâneas durante 60 segundos e veja seu servidor sofrer.<br />
<br />
Um exemplo de saída ao comando ab pode ser visto abaixo:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">This is ApacheBench, Version 2.3 <$Revision: 655654 $></span><br />
<span style="font-family: Courier New, Courier, monospace;">Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/</span><br />
<span style="font-family: Courier New, Courier, monospace;">Licensed to The Apache Software Foundation, http://www.apache.org/</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Benchmarking localhost (be patient)</span><br />
<span style="font-family: Courier New, Courier, monospace;">Finished 484 requests</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Server Software: Apache/2.2.20</span><br />
<span style="font-family: Courier New, Courier, monospace;">Server Hostname: localhost</span><br />
<span style="font-family: Courier New, Courier, monospace;">Server Port: 80</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Document Path: /sitecobaia/</span><br />
<span style="font-family: Courier New, Courier, monospace;">Document Length: 43666 bytes</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Concurrency Level: 10</span><br />
<span style="font-family: Courier New, Courier, monospace;">Time taken for tests: 30.022 seconds</span><br />
<span style="font-family: Courier New, Courier, monospace;">Complete requests: 484</span><br />
<span style="font-family: Courier New, Courier, monospace;">Failed requests: 0</span><br />
<span style="font-family: Courier New, Courier, monospace;">Write errors: 0</span><br />
<span style="font-family: Courier New, Courier, monospace;">Keep-Alive requests: 0</span><br />
<span style="font-family: Courier New, Courier, monospace;">Total transferred: 21502202 bytes</span><br />
<span style="font-family: Courier New, Courier, monospace;">HTML transferred: 21134344 bytes</span><br />
<span style="font-family: Courier New, Courier, monospace;">Requests per second: 16.12 [#/sec] (mean)</span><br />
<span style="font-family: Courier New, Courier, monospace;">Time per request: 620.291 [ms] (mean)</span><br />
<span style="font-family: Courier New, Courier, monospace;">Time per request: 62.029 [ms] (mean, across all concurrent requests)</span><br />
<span style="font-family: Courier New, Courier, monospace;">Transfer rate: 699.43 [Kbytes/sec] received</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Connection Times (ms)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> min mean[+/-sd] median max</span><br />
<span style="font-family: Courier New, Courier, monospace;">Connect: 0 0 0.2 0 2</span><br />
<span style="font-family: Courier New, Courier, monospace;">Processing: 349 614 108.0 608 950</span><br />
<span style="font-family: Courier New, Courier, monospace;">Waiting: 344 598 105.6 591 932</span><br />
<span style="font-family: Courier New, Courier, monospace;">Total: 349 614 108.0 608 950</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Percentage of the requests served within a certain time (ms)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 50% 608</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 66% 658</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 75% 688</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 80% 707</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 90% 750</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 95% 798</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 98% 845</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 99% 875</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 100% 950 (longest request)</span><br />
<br />
<br />
Alguns números mostrados são interessantes. Como por exemplo a média de requisições por segundo(Requests per second) que neste caso foi de 16,12. Quanto mais alto este número mais requisições seu servidor servirá em menos tempo. A média de tempo(Time per request) por requisição também é interessante de ser observada. Neste caso temos dois valores, o primeiro, indica o tempo médio em milisegundos que o servidor demorou para responder uma única requisição, neste caso 620,291 ms. Ou seja com 10 conexões concorrentes a resposta demourou em média pouco mais de meio segundo para chegar(1 segundo tem 1000 milisegundos). O segundo valor da média de tempo por requisição é o resultado da divisão do tempo total para todas as requisições(30,22 segundos ou 30022 milisegundos) pelo número de requisições completas (484) o que dá o valor de 62,029 milisegundos por requisição.<br />
<br />
No final temos um resumo da porcentagem de requsições respondidas dentro de um certo tempo em milisegundos. Observem que 50% das requisições demoraram no máximo 608 ms para serem respondidas. E a requisição mais demorada demorou 950 ms.<br />
<br />
Um resultado que pode deixar-nos confusos quando usamos o ab com sites dinâmicos é o seguinte:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">Failed requests: 32951</span><br />
<span style="font-family: Courier New, Courier, monospace;"> (Connect: 0, Receive: 0, Length: 32951, Exceptions: 0)</span><br />
<br />
<br />
Você pensa: "Porque ele reportou que 32951 requisições falharam?". Mas observe que o tipo de erro foi de tamanho(Length), isso acontece porque o ab considera que quando os tamanhos das respostas diferem da primeira resposta obtida do servidor acontece um erro de Length. Como em páginas dinâmicas coisas como identificadores de sessão, cookies ou até mesmo o conteúdo da resposta podem mudar de uma requisição para outra este tipo de "erro" pode aparecer frequentemente.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-10613379870547643812013-01-28T18:56:00.001-08:002013-01-28T18:56:56.046-08:00Código fonte de jogo flash opensourceOlá a todos.<br />
Acabei de criar um <a href="https://github.com/ricardosdl/darkmatters">repositório</a> no github com o código fonte de um pequeno jogo que criei usando Action Script 3 e a biblioteca <a href="http://flixel.org/">flixel</a>. O nome do jogo é DarkMatters.<br />
<br />
O jogo é bem simples e criei com a intenção de aprender mais sobre o processo de desenvolvimento de um jogo. Infelizmente o código não é de grande qualidade mas espero que possa ajudar alguém interessado no assunto.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-40737825351766622222013-01-22T10:00:00.000-08:002013-01-22T10:00:13.685-08:00Livros grátis para aprender PHPAqui vai um link que pode ser de muita ajuda para quem está querendo aprender como programar em PHP.<br />
<a href="http://www.linuxlinks.com/article/20130119004851789/9oftheBestFreePHPBooks-Part1.html">http://www.linuxlinks.com/article/20130119004851789/9oftheBestFreePHPBooks-Part1.html</a><br />
Neste link tem uma lista de 9 livros grátis sobre PHP. Aproveitem!Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-15520756254721265582012-12-18T17:45:00.002-08:002012-12-18T17:45:57.018-08:00WEB AdventAlguém aí já ouviu falar do <a href="http://webadvent.org/">PHP Advent</a> (que aparentemente este ano mudou o nome para WEB Advent)?<br />
<br />
Todo mês de dezembro, desde de 2007, várias pessoas são convidadas a escreverem artigos com dicas, conselhos, truques e o que mais estiver em suas mentes. Tem conteúdo sobre desenvolvimento de software, web, design, php etc. Os artigos são muito interessantes e são escritos por pessoas conhecidas na comunidade. Não perca mais tempo e acesse o <a href="http://webadvent.org/2012">WEB Adevent 2012</a>. Lá tem links para os anos anteriores também.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com1tag:blogger.com,1999:blog-4411317604583328279.post-1486288519923265132012-11-26T14:29:00.002-08:002012-11-26T14:29:56.352-08:00O Google cai e a internet cai!Hoje 26/09/2012 na parte da tarde serviços da Google como busca, e-mail e o youtube apresentaram <a href="http://tecnologia.uol.com.br/noticias/redacao/2012/11/26/apos-dificuldades-de-acesso-servicos-do-google-normalizam.htm">instabilidade</a> quando se tentava acessá-los.<br />
<br />
Notei duas coisas engraçadas no meu local de trabalho, primeiro foi uma garota que achou que a internet tinha "caído". O que até pode ser considerada uma reação normal quando muitas pessoas deixam a página inicial do browser apontada para o serviço de busca da Google (Se bem que neste particular caso de hoje os servidores da Google estavam retornando uma página de erro informando o status 502. Acho que ela é um pouco leiga na área).<br />
<br />
Outra coisa que notei foi que muitas pessoas não conhecem ou não se interessam por outras ferramentas de busca. Durante os vários minutos em que o serviços de busca não estavam funcionando a maioria resolveu que era era o momento ideal para uma um lanche ou tomar um café. Serviços como <a href="http://br.bing.com/">bing</a> ou <a href="http://br.yahoo.com/">yahoo</a> não são lembrados.<br />
<br />
Durante este sabático do serviço de busca da Google eu deve ter feito pelo menos umas 5 buscas, principalmente relacionadas a referência de funções PHP ou exemplos de código para alguma tarefa. Acontece que meu serviço de busca padrão é o pouco conhecido <a href="http://duckduckgo.com/">DuckDuckGo</a>. Preocupações relacionadas ao efeito "<a href="http://dontbubble.us/">bolha</a>" me levaram a esta decisão.<br />
<br />
Mas não pensem que sou algum radical que não usa mais a busca google. Na verdade ainda devo fazer mais buscas no google, no DuckDuckGo basta adicionar "!g" na frente dos termos de busca para que eu seja redirecionado para lá. Uso muitos serviços da Google que hospeda este blog, meu e-mail e muitos vídeos que assisto no youtube. Eu só tento evitar fazer buscas logado com minha conta Google, sempre tenho dois browsers abertos um com e-mail e Google Talk e outro para minhas buscas.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-69827459770357119512012-11-25T14:42:00.003-08:002012-11-25T14:42:28.880-08:00A Essencial e Difícil Arte de se Ler CódigoNas minhas andanças pela internet encontrei um artigo bem interessante chamado:<br />
<a href="http://www.gamasutra.com/blogs/RobertDieterich/20121122/182156/Most_Programmers_Cant_Read_Code.php">Most Programmers Can't Read Code</a><br />
<br />
Ou seja "A maioria dos programadores não conseguem ler código". Na verdade o que o autor do artigo realmente enfatiza é que a maioria dos programadores não conseguem ler código e compreendê-lo de modo efetivo.<br />
<br />
No artigo são citadas várias razões para esta conclusão como a percepção de que é mais fácil escrever código do que lê-lo. Ou que na hora de se ler o código temos que manter muito mais coisas em nossas mentes como as varáveis, estruturas de dados e o design do código em geral. Ainda temos o caso onde a diferença de experiência entre o programador que escreveu o código e o programador que está lendo-o entra em jogo.<br />
<br />
Eu realmente acho a atividade de se ler código legado, ou seja, código que não foi escrito por você ou que você escreveu a mais de uma semana, muito difícil de ser dominada de modo efetivo. Quando eu encontro um trecho de código que acho particularmente difícil de se compreender, seja por eu não se tão esperto quanto o cara que o escreveu ou o contrário, eu sempre achei a ajuda de <a href="https://en.wikipedia.org/wiki/Debugger">debuggers</a> providencial. A possibilidade de se ver a execução das instruções linha por linha, acompanhar as mudanças nos valores de variáveis e também acompanhar o fluxo de execução torna a carga mental muito mais amena. Não importa qual linguagem de programação você usa, aprenda a usar um <a href="http://netbeans.org/kb/docs/php/debugging.html">debugger</a> para ajudá-lo nestas horas. E claro, pratique suas habilidades lendo <a href="http://sourceforge.net/">muito</a> <a href="https://github.com/">código</a>!<br />
<br />
E você? Tem alguma técnica particular que usa na hora de ler código?Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com1tag:blogger.com,1999:blog-4411317604583328279.post-83937527118716353132012-10-30T15:44:00.000-07:002012-10-30T15:45:21.276-07:00Arrays PHP a fundoArtigo muito bom sobre como os arrays PHP funcionam por trás das cortinas: <a href="http://sheriframadan.com/2012/10/a-closer-look-into-php-arrays/">A Closer Look Into PHP Arrays: What You Don’t See</a>.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-18330856779077403042012-10-28T12:22:00.001-07:002012-10-28T12:22:14.761-07:00Uma nova função PHP por diaJá viu aquelas pessoas que na intenção de melhorar seu vocabulário tentam aprender uma nova palavra por dia? Com disciplina é uma prática fácil e eficiente de rapidamente expandir seu vocabulário.<br />
<br />
Acho que é uma abordagem interessante para se aprender mais sobre as funções nativas do PHP. E olha que já existe muita coisa <a href="http://www.php.net/manual/en/indexes.functions.php">implementada</a>. Algumas vezes já vi funções criadas por programadores que já existem nativamente no PHP. E quantas vezes ficamos nos perguntando se já existe uma função que pode fazer o que nós queremos?<br />
<br />
A minha dica é que podemos utilizar a técnica de uma nova função PHP por dia. Apenas para efeitos de estudo, obviamente você não vai achar um uso prático imediato para a maioria das funções que você estudar. E é obvio que também você não vai memorizar exatamente como a função funciona, sua lista de parâmetros etc. Isso serve mais para se criar uma lista de "referências" de funções. Uma vez que você gasta algum tempo lendo sobre uma nova função, ela ficará guardada em algum lugar de sua memória e um dia, quando você se deparar com uma situação onde a função pode ser usada, seu cérebro terá maiores chances de fazer a conexões necessárias e assim você se lembrará que já existe uma função que realiza aquela tarefa.<br />
<br />
Para ajudar a achar sua função PHP do dia, escrevei este pequeno script que usa dicas que já falei sobre o <a href="http://hipercodigo.blogspot.com.br/2011/01/todo-programador-vez-ou-outra-da-uma.html">manual php</a> e a <a href="http://hipercodigo.blogspot.com.br/2012/04/quantas-funcoes-linguagem-php-tem.html">quantidade de funções existentes no PHP</a>.<br />
<script src="https://gist.github.com/3969528.js"> </script>
<br />
Basicamente o script escolhe uma função aleatoriamente das funções "internal" do PHP, funções nativas, e te leva para a página do manual sobre ela. Acredito que o script pode ser facilmente alterado caso você queira mudar a browser usado ou obter o conteúdo de outra forma.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-67078761488970954612012-10-02T18:40:00.000-07:002012-10-02T18:41:08.092-07:00Achando a chave primária anterior e posterior de uma chave primária existenteEstava eu trabalhando em uma pequena aplicação e o cliente me pediu para acrescentar um recurso onde ele poderia navegar entre os registros um a um. É um esquema muito parecido com grids de dados. Você está no registro número 50 e tem dois botões, um te leva para o registro 49 e outro para o registro 51.<br />
<br />
Pensei rapidamente e primeira solução que veio foi obter todos os id's da tabela ordenados e desta forma usando o id atual obter o id imediatamente anterior e o id imediatamente posterior. Lembrando que os id's podem ter "falhas" entre eles, o registro depois do id 25 pode ser o registro de id número 30. Não é uma solução eficiente mas como a aplicação é pequena, vai ser usada por um pequeno número de usuários e aplicando o princípio "<a href="http://c2.com/cgi/wiki?PrematureOptimization">Premature Optimization is the root of all Evil</a>" eu decidi deixar assim mesmo.<br />
<br />
Mas mais tarde eu voltei a pensar sobre isso: "Puxa vida! Retornar 5000 valores para se usar apenas dois deles?! Deve existir uma solução que seja pelo menos elegante para este problema!". E existe! É possível retornar o id anterior e posterior de um dado id com apenas uma consulta, e aqui está ela:<br />
<br />
<script src="https://gist.github.com/3824350.js"> </script>
Que legal! Vai retornar somente o que preciso e não tem problemas com "falhas" entre os valores e caso o valor não exista será retornado NULL. Tudo o que você tem a fazer é passar o id de referência para que possam ser encontrados os valores imediatamente anterior e posterior a ele, neste exemplo eu passei o valor 100 os valores retornados foram 99 e 101.<br />
<br />
Eu não fiz nenhum teste de performance sério, mas usando a tabela students do banco de dados do <a href="http://hipercodigo.blogspot.com.br/2012/09/falar-sobre-aplicacoes-com-muitas.html">post anterior</a> sobre transações, que tem 5000 registros, a consulta por todos os id's demora em média 92ms no meu computador (o <a href="http://www.postgresql.org/docs/8.4/static/sql-explain.html">explain</a> da consulta indica uma leitura de todos os registros da tabela como era de se esperar). Esta nova consulta que retorna apenas o que precisamos levou apenas 12ms em média para retornar os resultados. Eu não conheço muito sobre sql ou bancos relacionais, portanto, é bem provável que existam formas melhores de se fazer o que eu fiz, mas espero que este pequeno exemplo possa ajudá-los.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-73404796470307117102012-09-11T18:41:00.001-07:002012-11-17T16:16:30.459-08:00Aplicações com muitas Transações ConcorrentesUma vez uma pessoa com quem trabalhei, por um breve período, me contou uma experiência que ela teve ao reescrever a lógica de uma aplicação diretamente no banco de dados. Eles passaram a usar triggers, stored procedures e funções que eram escritas e executadas no servidor de banco de dados. Eu perguntei a esta pessoa qual foi a razão deles terem feito isso. A pessoa me explicou que eles tiveram problemas de forçar a consistência das regras da aplicação quando muitos usuários acessavam a aplicação ao mesmo tempo. Por exemplo: A aplicação era usada em uma universidade para permitir que os alunos se registrassem para diferentes disciplinas. Ela reforçava regras para limitar a quantidade de alunos por disciplina e também para evitar que os alunos escolhecem disciplinas com horários conflitantes.<br />
<br />
A pessoa envolvida nesta reescrita me explicou que não era possível reforçar as regras da aplicação somente na linguagem de programação cliente. Que em ambientes como muitas transações concorrentes a aplicação cliente do banco de dados vez ou outra vai ler dados obsoletos e gerar resultados errados. Eu não estava tão certo quanto esta pessoa de que isso era verdade. Eu sei que os bancos de dados providenciam comandos, que podem ser iniciados a partir do cliente, para iniciar transações e persistir os dados envolvidos ou simplesmente não persistir nada. E também temos os <a href="http://www.postgresql.org/docs/8.4/static/transaction-iso.html">níveis de isolamento de transações</a>.<br />
<br />
Eu resolvi escrever um pequeno programa para testar se é realmente impossível escrever lógica de negócios usando uma linguagem de programação cliente, em um ambiente de muitas transações concorrentes. Para simular as muitas transações concorrentes eu vou usar o utilitário <a href="http://httpd.apache.org/docs/2.2/programs/ab.html">Apache Benchmark ou ab</a>.<br />
<br />
O banco de dados (<a href="http://hipercodigo.googlecode.com/files/dump_postgres.sql">dump postgres</a>) é bem simples e consiste de apenas três tabelas: students(id, name, date_of_birth), courses(id, name, workload) e students_courses(id_student, id_course). O servidor é postgres versão 8.4. Quanto aos dados temos 5000 estudantes e 500 cursos. A regra de negócio bem simples, cada curso pode ter no máximo 10 estudantes registrados. Ou seja, na tabela sutdents_courses um curso pode ter no máximo 10 linhas com seu id na coluna id_course.<br />
<br />
Quando o código da aplicação é executado ele escolhe um estudante e um curso ao acaso e tenta registrar este estudante para este curso escolhido. Primeiro a aplicação faz uma verificação para ver se o curso está disponível (verifica se existem menos de 10 estudantes registrados para o curso). Caso o curso esteja lotado o estudante não é registrado. Caso contrário uma linha é inserida na tabela students_courses.<br />
<br />
A minha primeira tentativa foi usando PHP junto com a versão mais recente do CodeIgniter. Que pode ser baixada aqui. O código principal é este aqui:<br />
<script src="https://gist.github.com/3703431.js"> </script>
<br />
Eu usei os comandos trans_start e trans_complete de acordo com a <a href="http://codeigniter.com/user_guide/database/transactions.html">documentação</a> deles.<br />
<br />
O teste de concorrência foi feito chamando-se o ab da seguinte maneira:<br />
ab -c 50 -t 30 http://localhost/www/transactions/index.php/course_registration_codeigniter_version<br />
<br />
Os parâmetros indicam que o servidor será acessado durante 30 segundos por 50 conexões simultâneas. O último parâmetro é a url do servidor.<br />
<br />
Depois do teste executando-se a seguinte consulta:<br />
<br />
<script src="https://gist.github.com/3703448.js"> </script>
Eu percebi que a regra da aplicação tinha sido violada. Existiam cursos com mais de 10 alunos. Após este primeiro teste me perguntei se isso poderia ter sido resultado da implementação interna do CodeIgniter. Não cheguei a investigar como o CodeIgniter implementa transações mas resolvi fazer outro teste. Desta vez usando um script php simples que por sua vez usa PDO para acesso ao banco de dados. A parte mais importante do código está logo abaixo:<br />
<script src="https://gist.github.com/3703457.js"> </script>
<br />
Mais uma vez o comando ab é executado apenas mudando-se a url:<br />
ab -c 50 -t 30 http://localhost/www/transactions/course_registration_pdo_sem_locks.php<br />
<br />
E mais uma vez eu vejo que a regra da aplicação foi quebrada com cursos com mais de 10 estudantes. Será que esta pessoa com quem trabalhei tinha razão?<br />
<br />
No meu teste usando-se apenas transações não foi o suficiente para garantir a integridade das regras da aplicação. Fiz algumas pesquisas e achei este <a href="https://docs.google.com/viewer?a=v&q=cache:FRArag5rizEJ:www.postgresql.org/files/developer/concurrency.pdf+&hl=en&pid=bl&srcid=ADGEESgpn3joeW_aln5cujhzKcajnVXGtQYiBcSLy6R9JoVvCXsJXkmnM7UkyjLCOc4pIXdbv1d_aXQvap3Zh-_k1CGKrGzOfyG4tG974QE_7PanaP02KuRkXxZ7dE8ARZfMloyzIPKO&sig=AHIEtbSgNPsKaul2ERjf96k7orocpLvk9Q&pli=1">documento</a>. Foi nele que ouvi falar do <a href="http://www.postgresql.org/docs/8.4/static/sql-select.html#SQL-FOR-UPDATE-SHARE">SELECT FOR UPDATE</a>. O que também não funcionou. O problema é que a opção bloqueia as linhas retornadas pelo SELECT executado de sofrerem operações as operações UPDATE, DELETE e SELECT FOR UPDATE. Como meu objetivo não é alterar nenhuma das linhas retornadas mas sim inserir na tabela o SELECT FOR UPDATE não adianta neste caso.<br />
<br />
O que eu realmente preciso é bloquear a tabela para que não sofra atualizações enquanto eu estou checando a regra da aplicação. Uma operação de <a href="http://www.postgresql.org/docs/8.4/static/sql-lock.html">LOCK</a>. Basicamente vou bloquear a tabela para que não sofra alterações, checar a regra da aplicação e desbloqueá-la no fim da transação. A parte principal do código está logo abaixo:<br />
<script src="https://gist.github.com/3703467.js"> </script>
Novamente testo com o comando ab:<br />
ab -c 50 -t 30 http://localhost/www/transactions/course_registration_pdo.php<br />
<br />
E agora sim. A regra da aplicação foi satisfeita, não temos mais cursos com mais de 10 alunos. Uma coisa que percebi foi que as consultas durante o teste aparentemente ficaram bem mais lentas, o LOCK de toda a tabela deve cobrar seu preço. Outra observação sobre o LOCK é que ele não faz parte do padrão SQL, portanto um código que possa rodar em diferentes bancos de dados deve ficar sob a responsabilidade do desenvolvedor.<br />
<br />
<h3>
Conclusão</h3>
Sim é possível utilizarmos uma linguagem de programação cliente para validarmos e reforçarmos as regras de aplicação com alta concorrência de transações. Mas para isso temos que usar recursos oferecidos pelo próprio banco de dados.<br />
<br />
Acredito que o uso de linguagens de programação cliente nestes casos traz facilidades de desenvolvimento e manutenção associadas aos recursos das linguagens e das bibliotecas disponíveis. Mas também temos que lembrar que existe o outro lado da moeda, apesar de não ter testado isso, acredito que haveria ganhos de velocidade significativos programando-se a lógica da aplicação diretamente no banco de dados.<br />
<br />
Como sempre não existe bala de prata, você deve analisar o contexto, requisitos e recursos disponíveis para tomar estas decisões.<br />
<br />
Todo o código da aplicação pode ser obtido <a href="http://hipercodigo.googlecode.com/files/transactions.zip">aqui</a>. Não se esqueça configurar os dados de acesso ao banco de dados nos arquivos pdo e no arquivo application/config/database.php.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-45966004032941553722012-08-18T14:04:00.003-07:002012-08-18T14:05:59.688-07:00Velocidade em PHPO comando <a href="http://www.php.net/manual/en/control-structures.foreach.php">foreach</a> é mais lento do que um simples <a href="http://www.php.net/manual/en/control-structures.for.php">for</a>? Usar aspas duplas ou simples para strings faz muita diferença no tempo de execução? <a href="http://www.php.net/manual/en/function.isset.php">isset()</a> é mais rápido do que <a href="http://www.php.net/manual/en/function.empty.php">empty()</a>? Este tipo de discussão é realmente útil?<br />
<br />
Um cara chamado Chris Vincent criou um site chamado <a href="http://phpbench.com/">The PHP Benchmark</a> para te ajudar a achar respostas para estas questões. Ele apresenta vários exemplos com uma breve descrição, os resultados obtidos por ele e o código usado em cada exemplo para que você possa testar você mesmo.<br />
<br />
Mas lembre-se! Geralmente seu maior gargalo de performance não está no seu código e sim na entrada e saída (bancos de dados, webservices, redes, sistemas de arquivos...)!Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-75134821520170371712012-07-28T13:48:00.000-07:002012-07-28T13:50:59.988-07:00Como exportar e fazer download de arquivos da aba Net do FirebugMuitos desenvolvedores web provavelmente conhecem e usam o <b>excelente </b>plugin <a href="http://getfirebug.com/">Firebug</a>. Ele é muito útil tanto para programadores quanto para designers. Mas hoje estou aqui para falar especificamente da aba Rede/Net mostrada abaixo:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS922T6qTcO6lzoDixYlORN9ijkT5ZoHLqlsY3mIIFUaw84PMf1H53JIBskUBbNmVxmOILfBKXcsNvqNdOjlc31ZD6HNXtGsxNAfdjkvvEn3X7TxRMRsCDLo5ErcmBoQE9TFG2L2JAyXc/s1600/aba_net_firebug.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Mostra a aba Rede Ou Net do Firebug listando os arquivos de um site" border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS922T6qTcO6lzoDixYlORN9ijkT5ZoHLqlsY3mIIFUaw84PMf1H53JIBskUBbNmVxmOILfBKXcsNvqNdOjlc31ZD6HNXtGsxNAfdjkvvEn3X7TxRMRsCDLo5ErcmBoQE9TFG2L2JAyXc/s640/aba_net_firebug.png" title="Aba Rede ou Net do Firebug" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Aba Rede ou Net Firebug</td></tr>
</tbody></table>
<br />
Ela lista todos os arquivos e seus respectivos tempos de download. Existem várias opções para listar somente imagens, arquivos de script ou css.<br />
<br />
Pouco tempo atrás eu precisei obter os dados desta aba. Eu tinha feito download de um jogo feito usando-se html5, e usando-se a opção "Arquivo->Salvar como" do browser muitos dos arquivos de imagens não foram obtidos, já que eles não são referenciados em tags img ou no css. Eu queria uma forma de exportar esta lista de arquivos para que eu pudesse usá-la em um script que me permitisse fazer o download dos arquivos não encontrados, ou seja os arquivos que o servidor reportou com erro 404 quando tentei rodar o jogo localmente em meu computador. Para o problema de exportar esta lista de arquivos da aba Rede já existe um plugin (um plugin para um plugin?!) que faz isso. Ele se chama <a href="https://getfirebug.com/wiki/index.php/Firebug_Extensions#NetExport">NetExport</a>. Depois de instalar o NetExport, na aba rede vai aparecer uma opção chamada <b>Export</b>, depois de clicar nesta opção é só clicar na opção "Save as...". No local indicado será criado um arquivo com a extensão .har. Se você abrir este arquivo poderá ver que o conteúdo dele está no formato json.<br />
<br />
Quando o conteúdo de um arquivo está no formato json, torna-se muito fácil ler tudo usando-se a função json_decode. Abaixo uma listagem do código que usei para a tarefa.<br />
<br />
<script src="https://gist.github.com/3194714.js">
</script>
<br />
<br />
Dependendo do seu caso você precisará mudar um pouco o código. Na listagem a url poderia ser "$entry->request->url" diretamente em muitos casos sem a necessidade de usar basename.<br />
<br />
Bom espero que o post seja útil para alguém, até mais!Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-39314312422245260162012-06-23T13:16:00.001-07:002012-06-23T13:17:18.313-07:00Porque usuários querem aplicações que façam tudo?Recentemente estive em uma reunião para discutir sobre o desenvolvimento de uma nova aplicação. A aplicação em si provavelmente será simples. Os usuários vão alimentá-la com informações, o programa armazena, efetua validações e algum processamento posterior usando as regras de negócio. Depois disso os usuários podem acessar estas informações ou exportá-las usando algum formato aberto para que possam ser usadas em outros programas.<br />
<br />
Nós temos um programa simples que faz pouca coisa e que exporta as informações armazenadas em um formato aberto, como texto por exemplo. Esta é basicamente a <a href="http://en.wikipedia.org/wiki/Unix_philosophy">filosofia unix</a> de se escrever programas. Acho que esta forma de pensar leva a programas mais fáceis de serem entendidos, com menos erros e mais fáceis de serem alterados.<br />
<br />
Voltando ao programa mencionado no início do texto, depois de definido o escopo principal o usuário começou a dar ideias de como programa deveria incluir um sistema de gerenciamento de compromissos. Marcar compromissos com data e hora, ter um calendário etc, tudo que estes sistemas de agendamento possuem. Vejam, ser um sistema de agendamento não é razão de existir deste novo programa, incluir um demandaria tempo de desenvolvimento. A princípio um sistema de agendamento não parece muito complicado de ser desenvolvido. Mas com alguns anos de experiência nesta indústria vital eu aprendi que nada é tão simples quanto parece a primeira vista quando se trata de desenvolvimento de software. Não é toa que muitos <a href="http://spectrum.ieee.org/computing/software/why-software-fails/0">projetos de software</a> demoram mais tempo para ser desenvolvidos e saem mais caros do que inicialmente previsto.<br />
<br />
Eu imagino que para as pessoas leigas software é uma coisa simples de ser criada e principalmente alterada. Quando o contrário disso deve estar mais próximo da verdade. E soma-se a isso os inflados egos que permeiam o meio dos desenvolvedores de software. "É claro que podemos desenvolver um sistema de agendamento perfeitamente funcional dentro do prazo e custo esperado. Você acha que nós somos amadores?".<br />
<br />
Quanto ao sistema que mencionei? Provavelmente ele vai exportar as informações no formato <a href="http://support.google.com/calendar/bin/answer.py?hl=en&answer=45656&topic=1672003&ctx=topic">csv</a> e diremos para o usuário usar o <a href="https://www.google.com/calendar">Google Calendar</a>, que acredito que seja um excelente software e o melhor de tudo é grátis.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-33743927580067389172012-05-25T20:29:00.000-07:002012-05-26T13:12:32.095-07:00PHP One-liners ou Incríveis coisas que você pode fazer em PHP com apenas uma linha de códigoUma linguagem de programação é considerada expressiva quando você consegue fazer coisas úteis sem precisar escrever muito código. Devido a sua extensa biblioteca de funções e sua natureza dinâmica a linguagem PHP é uma linguagem expressiva. E aqui vão alguns exemplos desta expressividade.<br />
<br />
<h2>
1. Validar Email</h2>
<script src="https://gist.github.com/2791904.js">
</script>
<br />
<h2>
2. Converter Endereço IP para um número inteiro e vice-versa(útil para armazenamento)</h2>
<script src="https://gist.github.com/2791907.js">
</script>
<br />
<div>
<br />
<h2>
3. Filtrar uma lista de números(usa closures)</h2>
<script src="https://gist.github.com/2791911.js">
</script>
</div>
<div>
<br /></div>
<div>
<h2>
4. Ler um arquivo</h2>
<script src="https://gist.github.com/2791914.js">
</script>
</div>
<div>
<br /></div>
<h2>
5. Somar uma lista de números</h2>
<script src="https://gist.github.com/2791917.js">
</script>
<br />
<div>
<br /></div>
<h2>
6. Achar o menor ou maior número de uma lista</h2>
<script src="https://gist.github.com/2791922.js">
</script>
<br />
<div>
<br /></div>
<h2>
7. Gerar e imprimir o alfabeto</h2>
<script src="https://gist.github.com/2791939.js">
</script>
<br />
<h2>
8. Imprimir as linhas de um arquivo ignorando as linhas vazias</h2>
<script src="https://gist.github.com/2791950.js">
</script>
<br />
<div>
<br /></div>
<div>
<h2>
9. Gerar uma senha de 8 caracteres aleatória</h2>
<script src="https://gist.github.com/2791954.js">
</script>
</div>
<h2>
10. Comprimir e descomprimir uma string muito longa</h2>
<script src="https://gist.github.com/2791958.js">
</script>
<br />
<div>
<br /></div>
<br />
Espero que seja útil.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-36704078044182359242012-05-04T16:27:00.002-07:002012-05-04T16:30:06.509-07:00Coisas que você não deve colocar no Banco de DadosEm minhas andanças pela internet eis que me deparo com um ótimo <a href="http://www.revsys.com/blog/2012/may/01/three-things-you-should-never-put-your-database/">artigo </a>chamada "Três coias que você nunca deve por no banco de dados". É um ótimo artigo, recomendo a leitura.<br />
<br />
Basicamente ele fala que evitar armazenar dados binários(imagens, arquivos...), dados efêmeros (informações que são usadas por um curto período de tempo) e logs.<br />
<br />
Eu concordo com o que é dito no artigo. Mas venho aqui falar de outra coisa que jamais em hipótese alguma você deve armazenar no banco de dados. Estou falando de <b><i><u>CÓDIGO</u></i></b>. E aqui estou falando de código mesmo, o mesmo código que você escreve quando está criando uma aplicação.<br />
<br />
"O quê? Armazenar código? Isso é totalmente estúpido, quem em sã consciência faria isso?" Devem ser perguntas que permeiam sua mente agora. Mas me pesa muito dizer que já vi isso no mundo real, em uma aplicação web, e o pior de tudo é que eu tive que dar manutenção neste pesadelo.<br />
<br />
Veja, com uma parte do código de sua aplicação armazenada no banco de dados coisas simples e corriqueiras como testar sua aplicação, corrigir um pequeno bug, versionar a aplicação, atualizá-la e simplesmente ler o código se tornam tediosas, demoradas e tremendamente propensas a erros.<br />
<br />
Quando ocorre um erro no seu código o erro está no código que está dentro ou fora do banco de dados? Ou é um erro que depende de mudanças nos dois códigos? Quando você quiser ler o código para saber o que está errado você tem que manter sua IDE ou editor de texto abertos juntamente com um cliente de banco de dados. A cada novo trecho de código que você quiser ler você tem que fazer uma consulta no banco de dados. E quando você fizer uma alteração no código armazenado no BD você necessitará fazer uma operação de atualização no BD e depois rodar sua aplicação, torcendo para que não tenha cometido nenhum erro de sintaxe ou vai ter que refazer todo este processo. E como desenvolver em conjunto com uma equipe? Os desenvolvedores vão trabalhar juntos em um mesmo banco de dados e correr o risco de um sobrescrever alterações do outro? Ou cada vai ter seu banco de dados e depois sabe-se lá como eles vão sincronizar os códigos de cada um.<br />
<br />
Olha eu já vi ideias ruins na área de TI, e algumas delas são minhas mesmo, mas isso de armazenar código da aplicação no banco de dados é de longe a mais abominável de todas. Aqui fica o aviso amigos.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com1tag:blogger.com,1999:blog-4411317604583328279.post-41590583835050832522012-04-18T12:22:00.002-07:002012-04-18T12:25:57.719-07:00Chamar Terminais Virtuais em um SO Linux virtualizado no Virtual BoxTrabalho com máquinas virtuais usando o <a href="https://www.virtualbox.org/">VirtualBox</a>. Um pequeno e excelente programa para virtualização pelo qual você não precisa desembolsar nenhum centavo para usar. Geralmente eu uso máquinas virtuais para fazer testes ou experimentos sem correr o risco de fazer algo errado com minha máquina de trabalho.<br />
<br />
Recentemente em um destes experimentos com máquinas virtuais, um Linux Ubuntu 10.04, a interface gráfica ficou paralisada. Fiquei alegre que isso não foi na máquina host, e percebi que poderia tentar continuar usando máquina com a interface gráfica paralisada usando os <a href="http://en.wikipedia.org/wiki/Pseudo_terminal">terminais virtuais</a>, que geralmente são acionados através da combinação de teclas Ctrl + Alt + F1 até F7. Os terminais de F1 até F6 são em modo texto e o F7 é o que exibe a sua interface gráfica. O problema é que apertando estas sequências de teclas eram acionados os terminais virtuais na minha máquina host e não na máquina virtual. Como simular esta sequência de teclas na máquina virtual rodando no <b>Virtual Box</b>?<br />
<b>Host Key + F1</b> (a host key geralmente é o Control direito no teclado)<br />
Ou<br />
<b>F1, depois Ctrl e Alt</b> (esta combinação também acionou o terminal na minha máquina host, mas quando voltei para o terminal F7 a máquina guest também estava no terminal virtual)<br />
<br />
Muito útil para mim! Espero que ajude vocês.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-50104738717271459652012-04-04T07:13:00.007-07:002012-10-28T11:43:51.149-07:00Quantas funções a linguagem PHP tem?<b>8610</b><br />
De acordo com o <a href="http://www.php.net/manual/en/indexes.functions.php">manual</a> esta é a quantidade de funções que a linguagem PHP oferece. Usei o seguinte código javascript + jquery para chegar a este número:<br />
<script src="https://gist.github.com/2301350.js">
</script><br />
<br />
E olha que todas estas funções estão no namespace global da linguagem. Mas também estão incluídas funções presentes em extensões como mysql, gd, simplexml etc.<br />
<br />
Por isso eu não falo nada quando dizem que PHP é uma linguagem cujo design é feito por acidente. Mas isso não <a href="http://www.codinghorror.com/blog/2008/05/php-sucks-but-it-doesnt-matter.html">importa</a>.<br />
<br />
Update:<br />
Neste <a href="http://forums.devshed.com/showpost.php?p=1655063&postcount=11">link</a> no fórum devshed tem um comando que permite saber a quantidade de funções definidas no seu ambiente. A função <a href="http://br.php.net/manual/en/function.get-defined-functions.php">get_defined_functions</a> retorna um array com todas as funções definidas, divididas em "internal", as funções definidas pelo php, e "user", funções definidas pelo usuário. Aqui está o comando:<br />
<br />
$f = get_defined_functions();<br />
echo "Functions: ".count($f["internal"])."\n";<br />
<br />
No meu ambiente<br />
<br />
PHP 5.3.3-1ubuntu9.10 with Suhosin-Patch (cli) (built: Feb 11 2012 06:40:29)<br />
Copyright (c) 1997-2009 The PHP Group<br />
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies<br />
with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans<br />
<br />
são reportadas <b>1762</b> funções do tipo internal.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0tag:blogger.com,1999:blog-4411317604583328279.post-61566437760463883082012-03-26T20:13:00.001-07:002012-03-26T20:16:36.266-07:00Jogo Side-Scroller para aprender SDL e CEste aqui é um vídeo de um pequeno jogo que estou desenvolvendo usando <a href="http://www.libsdl.org/">SDL</a> e C. Enquanto desenvolvo o jogo vou aprendendo um pouco dos dois.<br />
<div class="separator" style="clear: both; text-align: center;"><object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/FC5_0sSEYsc/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/FC5_0sSEYsc?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><embed width="320" height="266" src="http://www.youtube.com/v/FC5_0sSEYsc?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash"></embed></object></div>É um jogo no estilo side-scroller, 2D daqueles que para quem viveu a fase de videogames como <a href="http://pt.wikipedia.org/wiki/Super_Nintendo_Entertainment_System">Super-Nes</a> e <a href="http://pt.wikipedia.org/wiki/Mega_Drive">Mega Drive</a> vai trazer algumas boas lembranças! Mas ainda falta muita coisa para ser feita.Ricardo Soares de Limahttp://www.blogger.com/profile/02673288481541957998noreply@blogger.com0