Jekyll2021-10-06T16:54:25+00:00https://dmts.es/DMTSTecnologías de la información geográfica, análisis de datos y software libreTesting I2021-10-05T00:00:00+00:002021-10-05T00:00:00+00:00https://dmts.es/testing_I<blockquote>
<p>Nadie quiere hablar sobre <em>testing</em>. <em>Testing</em> es el patito feo del desarrollo de software. El problema es que todos/as sabemos que el testeo es importante y que no lo hacemos lo suficiente. Y sentimos que nuestros proyectos no van tan bien como deberían y que probablemente más testeo haría que fueran mejor. Pero entonces leemos un libro sobre <em>testing</em> e instantaneamente nos venimos abajo con los múltiples tipos de testeos y las múltiples formas de hacerlos. No hay forma de que añadamos todo eso y aún nos de tiempo a programar.</p>
</blockquote>
<p><strong>Extreme Programming explained</strong> - Kent Beck</p>Nadie quiere hablar sobre testing. Testing es el patito feo del desarrollo de software. El problema es que todos/as sabemos que el testeo es importante y que no lo hacemos lo suficiente. Y sentimos que nuestros proyectos no van tan bien como deberían y que probablemente más testeo haría que fueran mejor. Pero entonces leemos un libro sobre testing e instantaneamente nos venimos abajo con los múltiples tipos de testeos y las múltiples formas de hacerlos. No hay forma de que añadamos todo eso y aún nos de tiempo a programar.Importar funciones de otro paquete en R2021-08-06T00:00:00+00:002021-08-06T00:00:00+00:00https://dmts.es/importacion-paquetes-metodos-R<p>Para <strong>usar una función de otro paquete</strong> en un paquete que estamos creando , necestiamos añadirlo a la sección <strong>Imports</strong> del <code class="highlighter-rouge">DESCRIPTION</code> y en el código, referirnos a la función de la forma <code class="highlighter-rouge">paquete::función</code>.</p>
<p>En el caso de funciones que usemos constantemente y especialmente para el caso de operadores (por ejemplo <code class="highlighter-rouge">%>%</code>), podemos <strong>evitar usar la notación <code class="highlighter-rouge">paquete::</code></strong> usando</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="err">#'</span><span class="w"> </span><span class="o">@</span><span class="n">importFrom</span><span class="w"> </span><span class="n">paquete</span><span class="w"> </span><span class="n">funcion</span></code></pre></figure>
<p>Para importar <strong>métodos de una clase S3 que no están explícitamente exportados</strong> en su paquete, algo que sucede habitualmente para funciones como <code class="highlighter-rouge">plot</code> o <code class="highlighter-rouge">predict</code>. Por ejemplo, para poder usar el predict del paquete randomForest, es necesario tener <code class="highlighter-rouge">Depends: randomForest</code> en <code class="highlighter-rouge">DESCRIPTION</code> y además importar el <code class="highlighter-rouge">predict</code>genérico del namespace <strong>stats</strong> con</p>
<div class="language-R highlighter-rouge"><pre class="highlight"><code><span class="cd">#' @importFrom stats predict
</span></code></pre>
</div>
<h3 id="referencias">Referencias</h3>
<ul>
<li>Libro <a href="https://r-pkgs.org/description.html#dependencies">R packages</a>.</li>
<li>https://stackoverflow.com/a/15563774
https://stackoverflow.com/questions/15563640/importing-s3-method-from-another-package</li>
</ul>Para usar una función de otro paquete en un paquete que estamos creando , necestiamos añadirlo a la sección Imports del DESCRIPTION y en el código, referirnos a la función de la forma paquete::función.Understanding Software I2020-09-20T00:00:00+00:002020-09-20T00:00:00+00:00https://dmts.es/understanding_software_I<p>Max Kanat-Alexander, en su libro “<a href="https://www.codesimplicity.com/post/understanding-software/">Understanding Software</a>” nos revela cual es la “forma correcta” (“<em>the right way</em>”) de escribir código (la traducción es mía):</p>
<blockquote>
<p>El código que mantiene su simplicidad a la vez que proporciona la flexibilidad necesaria para realizar posibles mejoras razonables en el futuro estaría diseñado de la manera correcta.
Se usan muchas excusas para no resolver los problemas de la forma correcta:</p>
<ul>
<li>No conozco la forma correcta.</li>
<li>El grupo no se pone de acuerdo en cuál sería la forma correcta.</li>
<li>Estoy demasiado cansado/hambriento/desanimado para hacerlo de la forma correcta en este momento.</li>
</ul>
</blockquote>
<p>Understanding Software. Max Kanat-Alexander. 2017 Packt Publishing</p>Max Kanat-Alexander, en su libro “Understanding Software” nos revela cual es la “forma correcta” (“the right way”) de escribir código (la traducción es mía):Dos notas sobre los triggers en PostgreSQL2020-08-13T00:00:00+00:002020-08-13T00:00:00+00:00https://dmts.es/pasar_argumentos_trigger_postgres<p>Para crear <em>triggers</em> (disparadores) en PostgreSQL hay que generar dos objetos:</p>
<ul>
<li>Una función trigger que realiza las acciones que se quiera.</li>
<li>El <em>trigger</em> propiamente dicho, que es el que se encarga de enlazar la función con una tabla y establecer en qué casos se va a lanzar.</li>
</ul>
<p>Algunas notas:</p>
<ul>
<li>El trigger no lleva schema en el nombre. Los triggers se crean específicamente para cada tabla, por lo que su nombre debe ser único sólamente entre los otros triggers de esa tabla.</li>
<li>La función trigger no puede llevar argumentos en su definición. Sin embargo, cuando es llamada por un trigger, se generan varias variables especiales en su interior, una de las cuales, TG_ARGV, es un array (empieza en 0) de texto de los argumentos pasados en la sentencia <code class="highlighter-rouge">CREATE TRIGGER</code>.</li>
</ul>Para crear triggers (disparadores) en PostgreSQL hay que generar dos objetos: Una función trigger que realiza las acciones que se quiera. El trigger propiamente dicho, que es el que se encarga de enlazar la función con una tabla y establecer en qué casos se va a lanzar.Programación funcional2019-11-06T00:00:00+00:002019-11-06T00:00:00+00:00https://dmts.es/post/programacion_funcional<blockquote>
<p>Los tres principales criterios de la programción funcional como paradigma de computación se pueden resumir:</p>
<ol>
<li>Cualquier operación se puede expresar como una llamada a una función.</li>
<li>El resultado de la llamada está definido únicamente por los valores de los argumentos.</li>
<li>El efecto de la llamada a una función es simplemente el valor devuelto.</li>
</ol>
</blockquote>
<p>John M. Chambers. <a href="https://www.crcpress.com/Extending-R/Chambers/p/book/9781498775717">Extending R</a>.</p>Los tres principales criterios de la programción funcional como paradigma de computación se pueden resumir: Cualquier operación se puede expresar como una llamada a una función. El resultado de la llamada está definido únicamente por los valores de los argumentos. El efecto de la llamada a una función es simplemente el valor devuelto.Renombrar ficheros con git2019-10-17T00:00:00+00:002019-10-17T00:00:00+00:00https://dmts.es/post/git_renombrar<p>Para renombrar un fichero que está dentro de un repositorio git y seguir haciéndole seguimiento, se pueden utilizar los comandos individuales:
<!--more--></p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code>mv nombre_antiguo nombre_nuevo
git rm nombre_antiguo
git add nombre_nuevo
</code></pre>
</div>
<p>o usar el atajo</p>
<div class="language-shell highlighter-rouge"><pre class="highlight"><code>git mv nombre_antiguo nombre_nuevo
</code></pre>
</div>
<p>Ambas opciones son equivalentes.</p>
<p>Si después se quieren ver los commits que han afectado a ese archivo, con</p>
<div class="language-shell highlighter-rouge"><pre class="highlight"><code>git log nombre_nuevo
</code></pre>
</div>
<p>sólo se obtendrán los commits realizados desde el cambio de nombre. Si se quieren visualizar todos los commits que le han afectado, incluyendo los anteriores al cambio de nombre, se puede realizar mediante:</p>
<div class="language-shell highlighter-rouge"><pre class="highlight"><code>git log --follow nombre_nuevo
</code></pre>
</div>Para renombrar un fichero que está dentro de un repositorio git y seguir haciéndole seguimiento, se pueden utilizar los comandos individuales:Inicio de arrays2019-09-14T00:00:00+00:002019-09-14T00:00:00+00:00https://dmts.es/indices-de-arrays<p>Recientemente le comentaba a un compañero que en R los índices de los arrays (sus equivalentes, vectores, listas, etc) empezaban en uno. Su respuesta fue elocuente:</p>
<blockquote>
<p>1?? herejia!</p>
</blockquote>
<p>Aunque no sea un lenguaje de programación, también en Postgres los arrays empiezan la cuenta en 1. Junto con AWK, y Matlab/Octave son de los pocos que no empiezan por cero.</p>
<p>Y aunque se suelen escuchar distintos motivos sobre el porqué los índices de los arrays empiezan en cero (algo que resulta poco intuitivo en principio), parece que realmente poca gente conoce los motivos reales.</p>
<p>En su interesante artículo <a href="http://exple.tive.org/blarg/2013/10/22/citation-needed/">Citation Needed</a>, Mike Hoye hace una investigación muy completa para encontrar la solución.</p>
<figure class="image">
<img src="../images/arrays_0_1.png" alt="XKCD Volume 0. Munroe, Randall." />
<figcaption>XKCD Volume 0. Munroe, Randall.</figcaption>
</figure>Recientemente le comentaba a un compañero que en R los índices de los arrays (sus equivalentes, vectores, listas, etc) empezaban en uno. Su respuesta fue elocuente:Escritura de funciones ‘tidy’2018-05-25T00:00:00+00:002018-05-25T00:00:00+00:00https://dmts.es/escribir-funciones-R<p><a href="http://hadley.nz/">Hadley Wickham</a> nos cuenta en su <em>The tidy tools manifesto</em><sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>, algunas de sus claves a la hora de escribir funciones (la traducción es mía):</p>
<blockquote>
<ul>
<li>Esforzarse por mantener las funciones tan simples como sea posible (¡pero no más!). Generalmente, cada función debería hacer una cosa bien, y el propósito de la función se debería poder definir en una sola frase.<!--more--></li>
<li>Evitar mezclar efectos secundarions (<em>side-effects</em>) con transformaciones. Asegurarse que cada función o devuelve un objeto o tiene un efecto secundario. No ambas.</li>
<li>Los nombres de las funciones deberían ser verbos. La excepción es cuando muchas funciones usan el mismo verbo (normalmente algo como “modificar”, “añadir” o “calcular”). En ese caso, evitar duplicar el verbo común y en su lugar centrarse en el nombre. En ggplot2 hay un buen ejemplo de esto: casi cualquier función añade algo a un gráfico ya existente.</li>
</ul>
</blockquote>
<div class="footnotes">
<ol>
<li id="fn:1">
<p><a href="https://cran.r-project.org/web/packages/tidyverse/vignettes/manifesto.html">https://cran.r-project.org/web/packages/tidyverse/vignettes/manifesto.html</a> <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>Hadley Wickham nos cuenta en su The tidy tools manifesto1, algunas de sus claves a la hora de escribir funciones (la traducción es mía): https://cran.r-project.org/web/packages/tidyverse/vignettes/manifesto.html ↩Programas para usar git2018-05-02T00:00:00+00:002018-05-02T00:00:00+00:00https://dmts.es/post/programas-para-usar-git<p>En general utilizo bastante los comandos en terminal (por cierto, suelo usar <a href="http://guake.org/">Guake</a> como emulador de terminal) directamente. Tengo definidos algunos alias para tareas comunes, no como alias en git, si no directamente en Bash<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>.
<!--more--></p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">alias </span><span class="nv">add</span><span class="o">=</span><span class="s1">'git add'</span>
<span class="nb">alias </span><span class="nv">br</span><span class="o">=</span><span class="s1">'git branch -v'</span>
<span class="nb">alias </span><span class="nv">cambios</span><span class="o">=</span><span class="s1">'git log --date-order --date=short --graph --full-history --all --pretty=format:"%h - %ad - %s"'</span>
<span class="nb">alias </span><span class="nv">cambios_autor</span><span class="o">=</span><span class="s1">'git log --date-order --date=short --graph --full-history --all --pretty=format:"%h - %ad - %an - %s"'</span>
<span class="nb">alias </span><span class="nv">ci</span><span class="o">=</span><span class="s1">'git commit -m'</span>
<span class="nb">alias </span><span class="nv">cia</span><span class="o">=</span><span class="s1">'git commit -a -m'</span>
<span class="nb">alias </span><span class="nv">co</span><span class="o">=</span><span class="s1">'git checkout'</span>
<span class="nb">alias </span><span class="nv">cob</span><span class="o">=</span><span class="s1">'git checkout -b'</span>
<span class="nb">alias </span><span class="nv">deshacer_ci</span><span class="o">=</span><span class="s1">'git reset --soft HEAD~1'</span>
<span class="nb">alias </span><span class="nv">gcaa</span><span class="o">=</span><span class="s1">'git commit -a --amend -C HEAD'</span>
<span class="nb">alias </span><span class="nv">nuevo</span><span class="o">=</span><span class="s1">'git log HEAD@{1}..HEAD@{0}'</span>
<span class="nb">alias </span><span class="nv">push</span><span class="o">=</span><span class="s1">'git push'</span>
<span class="nb">alias </span><span class="nv">pushom</span><span class="o">=</span><span class="s1">'git push origin master'</span>
<span class="nb">alias </span><span class="nv">st</span><span class="o">=</span><span class="s1">'git status'</span>
<span class="nb">alias </span><span class="nv">unstage</span><span class="o">=</span><span class="s1">'git reset HEAD'</span></code></pre></figure>
<p>Como interfaz gráfica suelo usar <em>git-cola</em>. Como visor de historial y de ramas no he llegado a encontrar ninguno que me guste demasiado, pero suelo usar el DAG que viene con git-cola o <code class="highlighter-rouge">gitk</code> que viene con la propia instalación de git.</p>
<p>Cuando trabajo con R, utilizo el panel de Git que incluye RStudio, ya que es lo más ágil.</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>En este <a href="https://github.com/damateos/dotfiles/blob/master/bash_aliases">gist</a> están todos los alias de <em>bash</em> que utilizo habitualmente. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>En general utilizo bastante los comandos en terminal (por cierto, suelo usar Guake como emulador de terminal) directamente. Tengo definidos algunos alias para tareas comunes, no como alias en git, si no directamente en Bash1. En este gist están todos los alias de bash que utilizo habitualmente. ↩Exportar issues de bitbucket a una tabla2018-04-06T00:00:00+00:002018-04-06T00:00:00+00:00https://dmts.es/post/leer-issues-bitbucket<p><strong>TL;DR:</strong> Una forma rápida de convertir la información principal de un fichero de <em>issues</em> exportado de Bitbucket a una tabla es usando el siguiente comando:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code>in2csv -f json -k issues archivo_exportado.json > tabla_salida.csv
</code></pre>
</div>
<!--more-->
<hr />
<p>Desde Bitbucket se pueden exportar los “issues” a un archivo json que guarda todos los datos relacionados con los mismos: contenido, comentarios, adjuntos, versiones, logs, etc. Aunque es un formato <sup id="fnref:formato"><a href="#fn:formato" class="footnote">1</a></sup> muy completo, que permite exportar e importar cómodamente entre repositorios git, no es lo más cómodo para ser leido por personas (es lo que tiene el json, muy fácilmente procesable por máquinas, pero aunque legible por humanos, no es especialmente amigable).</p>
<p>A veces es útil poder visualizarlos en un formato más cómodo, para, por ejemplo, poder trabajarlos en el marco de la gestión de proyectos con personas que no trabajen habitualmente con código.</p>
<p>Una forma rápida de extraer parte de la información es a través del comando in2csv del paquete <sup id="fnref:csvkit"><a href="#fn:csvkit" class="footnote">2</a></sup> <a href="https://csvkit.readthedocs.io">csvkit</a>. En este caso, nos quedaríamos con las características principales (estatus, prioridad, tipo, titulo y contenido, usuario que reporta, etc) y se quedarían fuera comentarios, adjuntos y otras informaciones.</p>
<p>En primer lugar hay que descomprimir el archivo que se genera al exportar desde Bitbucket y quedarse con el fichero llamado <code class="highlighter-rouge">db-1.0.json</code> o similar.</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code>in2csv -k issues archivo_exportado.json > tabla_salida.csv
</code></pre>
</div>
<p>Tras el parámetro <code class="highlighter-rouge">-k</code> hay que indicar la clave “top-level” que se quiere extraer y es obligatorio si el JSON contiene más de una de estas claves. En nuestro caso, las claves son:</p>
<ul>
<li>issues,</li>
<li>comments,</li>
<li>attachments,</li>
<li>logs,</li>
<li>meta,</li>
<li>components,</li>
<li>milestones</li>
<li>versions</li>
</ul>
<div class="footnotes">
<ol>
<li id="fn:formato">
<p>En <a href="https://confluence.atlassian.com/bitbucket/issue-import-export-data-format-330796872.html">esta página</a> se puede encontrar una descripción del formato. <a href="#fnref:formato" class="reversefootnote">↩</a></p>
</li>
<li id="fn:csvkit">
<p><strong>csvkit</strong> es un conjunto de herramientas de línea de comandos, escritas en Python, para trabajar con ficheros CSV. <a href="#fnref:csvkit" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>TL;DR: Una forma rápida de convertir la información principal de un fichero de issues exportado de Bitbucket a una tabla es usando el siguiente comando: