2 Buenas prácticas de programación

2.1 Programación defensiva

Las personas somos malas escribiendo códigos

Esta sección está basada en los trabajos y recursos publicados por Nick Eubank.

  • La filosofía de escribir un código está motivada por el hecho de que las personas somos malas escribiendo códigos.
  • Si queremos evitar errores no es suficiente con ser cuidadoso(a)
  • Es necesario diseñar estrategias que tomen en cuenta el hecho de que vamos a cometer errores al escribir un código.
  • Tener buenas estrategias es más relevante cuando existe trabajo colaborativo, que puede amplificar los errores.

En esta sección revisaremos cuatro buenas prácticas de programación. Estas prácticas no son solo aplicables a Stata, más bien son guías generales para escribir códigos en cualquier lenguaje de programación.

  1. Usar pruebas o tests.
  2. No duplicar información.
  3. No transcribir información, siempre exportarla.
  4. Usar un estilo correcto.

Con estos elementos podremos:

  • Minimizar las oportunidades de generar errores al codificar.
  • Maximizar la probabilidad de que cuando se cometa un error (lo que ocurrirá!) se pueda detectar con mayor facilidad.

¿Necesito entender estos principios?

Chang and Li (2015) testearon la reproducibilidad de 67 artículos publicados. Todos con alguna sección empírica. Encuentran que:

  • Solo 29 artículos fueron totalmente replicables.
  • 29 artículos tenían problemas al tratar missing values.
  • 9 poseen datos incorrectos o errores de codificación.

Christensen and Miguel (2018) indican que Chang and Li (2015) utilizan una versión poco estricta de replicabilidad.

(…) Chang and Li (2015) use a qualitative definition of replication, and test only key results of the paper, and this appears to lead to a fairly generous interpretation of replicability. (…)
(…) To our minds, this is evidence that even when data are available (which they sometimes are not) a non-negligible fraction of empirical economics research cannot be reproduced, even when using the original data and a relatively non-stringent conceptual understanding of what constitutes replication success.

¿Qué podemos aprender de esta historia?

  • Todos y todas tienen problemas para codificar (pasa hasta en las mejores familias).
  • Hoy el trabajo es colaborativo. También tienes que confiar en los demás.
  • Hay cosas que no se pueden resolver con ser cuidadoso(a) al codificar. ¿Si los datos están mal?
  • Reproducibilidad y replicabilidad son claves. Buenas referencias sobre estos temas se encuentran en la página de Julia Schulte-Cloos.

2.1.1 Práctica I: escribir una prueba o test

¿Qué significa escribir una prueba o test?

Nick Eubank indica que si él tuviese que elegir solo una práctica, elegiría agregar pruebas o tests a los códigos.

¿Qué es una prueba?

  • Son afirmaciones que tienen como respuesta un valor lógico (verdadero o falso).
  • Buscan chequear si una condición particular es cierta. En el caso de que no lo sea, es decir de que no se cumpla esta condición, la ejecución del código se detiene.

¿Por qué agregar estos chequeos, si yo siempre chequeo o reviso mis códigos?

1. Test se ejecutan cada vez que corres tu código

  • La mayoría testea la primera vez que escribe un código.
  • Si hay algún apuro por terminar, el testeo del código disminuye rápidamente.
  • Si ya ha pasado algún tiempo desde la última vez que lo ejecuté, únicamente ejecuto el código y espero los resultados. Entender un código (incluso el que uno(a) mismo(a) escribió es difícil después de un tiempo).
  • Un error que se comete en una de las múltiples ediciones del código pueda ser detectado con facilidad al testear.

2. Genera el hábito de chequear permanentemente a un costo razonable

  • La mayoría se para a chequear los datos cuando detecta algún error o bien sospecha que existe un problema.
  • Si nos acostumbramos a escribir pruebas al final de los códigos o bien cada vez que se hagan cierto tipo de operaciones (ej. siempre después de unir bases de datos), iremos generando el hábito de chequear constantemente, pero sin invertir demasiado tiempo en revisiones posteriores.

3. Ayuda a detectar problemas rápidamente

  • Sé donde está el error. Puedo corregirlo rápidamente.

4. Escribir pruebas ayuda a detectar más problemas de los previstos

  • Los errores de un código se manifiestan de múltiples formas y muchas veces son consecuencia de errores anteriores.
  • Si tengo valores duplicados, mi estadística descriptiva estará mal.
  • El problema surge de no darle un tratamiento correcto a los valores duplicados. No surge de algún problema en el código que genera la estadística descriptiva.

2.1.1.1 El comando |assert|

Ejemplo: Para escribir pruebas en Stata utilizaremos el comando |assert|. Notar que este comando detiene la ejecución del código cuando la condición no se cumple.

Testear si la base de datos tiene 100 observaciones:

count 
assert `r(N)' == 100

Testear si la variable tasa_desempleo está en su rango:

assert tasa_desempleo > 0 & tasa_desempleo < 100

Testear si la variable edad es siempre positiva:

edad > 0

Ejercicio:

Instrucciones:

Preguntas:

  1. La base de datos World Development Indicator (WDI) tiene observaciones duplicadas. Escriba un test que falle cuando existen valores duplicados.
  2. Los países en la base de datos Polity deberían ser un subconjunto de los países que están en la base WDI. Escriba un test que falle debido a este problema.
  • Las soluciones de todos los ejercicios se encuentran aquí

¿Cuando escribir tests?

  • Después de juntar bases: Siempre incluir test después de utilizar un merge o bien de append.
  • Después de manipulaciones complejas de datos: Si piensas que fue difícil hacer un proceso, incluye un test.
  • Después de eliminar observaciones: Siempre incluir test después de utilizar un drop.

Regla general siempre que te veas a ti misma(o) revisando o chequeando algún segmento de código interactivamente escribe un test.

2.1.2 Práctica II: no duplicar información

  • Información debe estar expresada una sola vez en un código.
  • Si la información está en muchas partes en el código, tendrás que buscar todos esos lugares.

Ejemplo: Imaginemos que quiero eliminar todas las observaciones que toman un valor mayor a un cierto límite, 110 en este caso.

drop if var1 > 110 
drop if var2 > 110 
drop if var3 > 110 

Lo anterior funciona… ¿Cuál es el problema entonces?

  • Imaginemos que queremos cambiar el límite de 110 a 100. Del modo en que está escrito, vamos a tener que hacer cambios 3 veces!
  • Si estas restricciones se encuentran en distintas partes de tú código, se puede inducir un error.

Ejemplo: Para evitar el problema anterior, es mejor escribir:

local lim = 110 

    drop if var1 > `lim'
    drop if var2 > `lim' 
    drop if var3 > `lim' 

De esta forma, en caso de decidir cambiar la restricción, solo tendrás que hacer un cambio. Minimizando la posibilidad de cometer un error.

Ejercicio 2:

  • Todas las regresiones que se encuentran en el código tienen la misma base, es decir, el mismo conjunto de variables que se repite.

  • La idea es consolidar

la base con el fin de evitar duplicación de información.

  • Con este fin, agregar population como control en todas las regresiones. Nuevamente, no dupliques información.

2.1.2.1 Práctica III: nunca transcribir directamente información, todo automatizado

  • Nunca se debe transcribir resultados. Todo debe ser exportado de forma tal que pueda ser actualizado automáticamente.
  • No cumplir con esta práctica es una importante fuente de errores.
  • Errores de transcripción: Si me equivoco en el décimo decimal no es tan grave, si cambio un signo sí lo es.
  • Problemas para actualizar: Es probable que al actualizar un código (como sucede usualmente en cualquier proyecto), olvidemos traspasar los resultados.
  • ¿Cómo evitar este problema?
    • Para usuarios de \(\LaTeX\) cada resultado debe ser guardado en archivos .tex.
    • Hacer esto no solo con las tablas (ej. putexcel). También hacerlo con cualquier estadística que aparezca en el texto. (Por ejemplo, “El promedio de edad de la muestra es de 43 años”. Este 43 debe obtenerse automáticamente desde tu código, no debes transcribirlo.)
    • Para esto: debes generar el número que se desea citar. Convertirlo a string y guardarlo (ej. midato.tex). Llamarlo desde \(\LaTeX\) con \input{midato.tex}.
    • Para usuarios de Word es un poco más complejo, pero posible putdocx.
    • Otra alternativa es utilizar Stata Markdown.
    • Independiente de la estrategia que utilices la buena práctica guarda relación con el hecho de que el producto final (artículo académico, reporte, nota, etc) debe estar conectado con cualquier estadística que se genere dentro de un proceso de análisis de datos.

Ejemplo: importar una tabla desde Stata a \(\LaTeX\) directamente

eststo clear
eststo: reg polity gdp_per_cap
eststo: reg polity gdp_per_cap under5_mortality
esttab using nombredelarchivo.tex, replace ///
       title("Mis estimaciones")
  • Lo importante es que todo lo que se produzca en Stata debe ir directamente al producto final. Para una revisión detallada ver Stata to LaTeX Guide. Una excelente referencia para hacer tablas mucho más avanzadas.

Ejercicio 3:

Calcula el promedio de literacy_rate y guárdalo en una macro local. Generar un formato tal que solo tenga dos decimales. Guarda el valor como string en un archivo .tex en la misma carpeta.

2.1.3 Práctica IV: estilo importa

  • Estilo no se refiere a la estética del código ni al orden.

  • Tiene que ver con la facilidad con el que este se puede leer. Al igual que cuando se escribe, lo importante es ser claro.

  • Para ello tres aspectos son claves:

  1. Utilizar espacios. Usar espacios siempre después de utilizar un operador. Por ejemplo:
gen var1=var2+var3      /// Mal
gen var1 = var2 + var3  /// Bien
  • Con criterio…
hours + minutes / 60 + seconds / 3600 
hours + minutes/60 + seconds/3600
  1. Nombrar las variables para que sean informativas en sí mismas. No escribir var1, si puedes escribir: tasa_desempleo. Requiere más trabajo, pero facilita la lectura. Agregar las unidades en las etiquetas facilita la lectura (en porcentaje). o bien (== 1) para indicar una variable dicotómica.

  2. Escribir comentarios

  • Ejercicio para explicar en pocas palabras lo que se ha hecho.
  • Existe un equilibrio entre parsimonia y calidad del comentario.
  • Establecer el objetivo del comentario claramente es muy importante.
  • No hay una regla para escribir comentarios, pero sí algunos consejos (ver, Gentzkow and Shapiro (2014))
  • Utilizar imperativo si lo tiene que corregir otra persona (ej. modifica parámetros aquí, fija directorio).
  • Debe incluir suficiente contexto para que alguien que no trabaje directamente en eso entienda qué se debe hacer.
  • Los comentarios largos deben explicar secciones de código. Importante escribir el código por bloques.
  • La brevedad no debe afectar nunca la comprensión. Esto también aplica para los comandos (ejemplo de Michael Shill).

Ejemplo:

summarize var1
sum var1
su var1

2.2 Estilo de codificación en Stata

2.2.1 Ser ordenado no es condición suficiente para tener un buen estilo de codificación

  • Primera idea: Un buen estilo de codificación es seguir una estrategia. Hay ciertas guías, pero lo relevante es seguir una y ser consistente.
  • Los códigos tienen distintas audiencias. La primera es tu computadora. Si tu computadora no entiende tu código, es el peor de los mundos.
  • Una de las audiencias más importantes son tus colaboradores y colaboradoras. Si ellos/as no lo entienden, el problema es tuyo en primer lugar.
  • No hay un solo buen estilo. No hay una guía que pueda sustituir experiencia o estrategias ya probadas de trabajo de equipo.
  • Lo importante es tener estrategias y utilizarlas en la medida de que sea positivo para el producto final.
  • Ahora veremos algunas estrategias y buenas prácticas que pueden ayudar a mejorar el estilo de codificación individual y de tu equipo en base a dos referencias adicionales: y de una guía confeccionada por Michael Stepner.

2.2.2 Escribe códigos cortos

  • Ningún segmento de código debiese ser mayor a 100 - 150 caracteres.
  • Códigos largos, debiesen ser escritos de forma más pequeña como ado-files.
  • Si tienes dificultades para reducir un código a estos estándares, es probable que tengas que pensar en cómo estructurarlo de mejor forma.
  • Cada segmento de código o funciones debiesen tener un propósito claro e intuitivo para lectores experimentados en el lenguaje de programación que se esté utilizando.
  • Los do-files deben ser cortos y deben tener un objetivo claro.
  • Todo do-file debe tener un propósito que pueda ser explicado en una oración. De hecho, hay que hacerlo. En el preámbulo. Cada do-file debe indicar claramente su objetivo.
  • Un proyecto debería tener varios do-files con las siguientes características.
    • Cortos: Debes ser capaz de leer un do-file completo en pocos minutos y entender el objetivo. Una buena regla es que no sean más largos de 250 - 350 líneas. No es estricta esta regla. Hay ocasiones que se justifican códigos más largos. Lo importante es la claridad. No sacrificarla nunca.
    • Autocontenidos: Cada do-file interactúa con otros solo a través de los archivos que carga y de los que guarda. Es importante entender tu proyecto como un flujo estructurado con pasos predeterminados.
    • Enfocados: Un do-file cumple un propósito determinado. Cada parte se debe entender como un paso intuitivo para lograr ese propósito.

2.2.3 El nombre de las variables debe caracterizarla

  • Nombres adecuados reemplazan comentarios y hacen el código auto contenido.
  • Utilizar nombres completos. Abreviaciones solo en el caso de estar seguro que cualquier lector puede entenderlo sin ambigüedad.
  • Si se utilizan abreviaciones. Ser consistente. Utilizar siempre las mismas a lo largo del código. Documentarlas, especialmente con bases de datos complejas.
  • Cuando no se pueda ser suficientemente claro en un nombre, utilizar sí o sí para dar una descripción (ej. agregar unidad de medida, o qué tipo de variable es).
  • labels especifican información. (ej, edad con el label edad al 31 de enero es más informativa que edad y más corto que edad_31enero).
  • No utilizar nombres en dos (o más) archivos que no expliciten por qué son diferentes. Por ejemplo: version_final.do y version_final_ahorasiquesiestavezsi.do.
  • Los nombres pueden ser más cortos cuando se utilicen con frecuencia o el objeto esté inmediatamente después.

Ejemplo:

beta_mco = (educacion' * educacion)^(-1) * ///
           (educacion' * log_salarios)

Mejor escrito sería:

X = educacion
Y = log_salarios
beta_educ_salarios = (X'*X)^(-1)*(X'*Y) 
  • No ser tacaño(a) al nombrar variables, archivos, carpetas.
  • Probablemente lo escribas solo una vez. No ahorres espacio. Siempre pensar en la claridad.
  • Para el caso de una figura:
    • `c_

1.pdfes un pésimo nombre. +correlaciones.pdfes un mal nombre. +T1_CORRELACIONES_INGRESO_MORTALIDAD.PDFes un mejor nombre. * Para el caso de una carpeta: +datos/brutos/interregionales un mal nombre. +datos/brutos/Estimaciones Censo Interregional 2010 - 2021` es un buen nombre. * Estos nombres nos permiten pensar en el flujo lógico del proyecto sin tener que mirar los códigos nuevamente. Ayúdate constantemente.

2.2.4 Ten especial cuidado cuando uses álgebra en los códigos.

  • Separa el álgebra en partes. Por ejemplo, el siguiente código puede inducir a un error, dado que no está separado en partes.
gen pib_percapita_real = ///
    (cons + ggob + export - import - impuestos)* 10^6 ///
    /(indice_precios * poblacion_miles * 1000)

Este código es más largo, pero mucho más entendible:

gen pib_millones_nominal = ///
    (cons + ggob + export - import - impuestos)
gen pib_total_real = pib_millones_nominal * 10^6 ///
    / indice_precios
gen pop_total = poblacion_miles * 1000
gen pib_percapita_real = pib_total_real / pop_total 

2.2.5 Ser consistentes

  • Hay cosas de estilo que son solo un tema de gusto. Por ejemplo, hay quienes escriben nivel_empleo_anual y otras que escriben NivelEmpleoAnual.
  • No importa la elección de un estilo u otro. Lo que importa es que todas y todos los miembros del equipo utilicen la misma convención.

2.2.6 Chequear errores

  • Hemos aprendido que es importante escribir pruebas o testeos. Especialmente relevante después de operaciones complicadas o pegado de bases de datos.
  • Stata en algunas ocasiones indica los errores que se comenten, sin la necesidad de colocar estas pruebas. Por ejemplo:
gen string x = "hola"
gen y = x^2

Stata retorna el siguiente error:

type mismatch 
r(109);

Normalmente el error da suficiente información. A pesar de lo anterior, en algunas circunstancias, no es tan claro saber cuál es el error. Cuando ustedes se hayan encontrado con un error, que no les fue fácil descifrar, tienen que escribir un comentario que lo indique y explique. Facilitará mucho el trabajo colaborativo. Eviten que otras personas tengan que invertir tiempo descifrando los mismos errores que ustedes.

2.2.7 Separar tipos de códigos

  • Separar códigos lentos de los rápidos.
  • Códigos lentos que rara vez se piensan ejecutar idealmente debiesen estar separados de los códigos rápidos que se quieren ejecutar múltiples ocasiones.
  • Evito tener que ejecutar un código lento cada vez que necesito actualizar algún resultado.
  • Este criterio cambia en caso de que todos los códigos sean rápidos. Si todos son computacionalmente no demandantes, lo importante es respetar el flujo de trabajo y la claridad de los procesos de análisis.

2.2.8 Automatizar todo lo que se pueda automatizar

  • Todo lo que se pueda automatizar debe ser automatizado. Por ejemplo, escriban ado-files que cambien para subconjuntos. Que los iteradores tengan números que se obtengan a partir del código, no por algo que ustedes tengan que escribir.
  • Nunca hacer trabajo que vaya a obtener resultados de forma interactiva. Lo interactivo es siempre y únicamente para inspeccionar. En todo caso, al inspeccionar deberían hacer un código de todas formas. Esto les va a ayudar a saber qué estaban pensando en el primer momento que vieron los datos que quieren analizar.

2.2.9 Abstraer para eliminar pasos redundantes.

  • Abstraer con fines de hacer códigos más claros. No por otras razones. A nadie le importa saber que puedes abstraer demasiado, si nadie entiende la razón de hacerlo. La claridad es lo que más importa.
  • Abstracción es esencial para escribir un buen código por al menos dos razones:
    • Al eliminar la redundancia se reducen las posibilidades de cometer errores.
    • Aumenta la claridad. Para cualquier lector será más fácil leer un código no redundante.

Ejemplo: Supongamos que queremos ver la correlación espacial del consumo de papas fritas. Queremos testear si el consumo per-cápita de papas fritas está correlacionado con el consumo promedio per-cápita de las otras comunas de la misma región.

Primero tenemos que calcular el consumo per-cápita del resto:

egen total_pc_papitas = total(pc_papitas), by(region)
egen total_obs = count(pc_papitas), by(region)
gen consumo_papitas_resto_pc = ///
(total_pc_papitas - pc_papitas)/(total_obs - 1)

Ahora podemos ver si existe correlación. ¿Pero si queremos cambiar el nivel de agregación? Tal vez sí existe correlación, pero a nivel de área metropolitana.

Copiemos el código de nuevo y calculemos esto.

egen total_pc_papitas = total(pc_papitas), by(metroarea)
egen total_obs = count(pc_papitas), by(region)
gen consumo_papitas_restometro_pc = ///
(total_pc_papitas - pc_papitas)/(total_obs - 1)

Noten que hay un error. Se nos olvidó reemplazar región por metroarea. Este error se puede propagar si seguimos haciendo operaciones.

Una alternativa al copiar y pegar es escribir una función con propósito general (ado-file, programa, función, etc) que calcule la variable que deseamos bajo distintos parámetros (noten que esto se relaciona con automatizar)

program consumo_papitas_resto 
    syntax, invar(varname) outvar(name) byvar(varname)
    tempvar tot_invar count_invar 
    egen `tot_invar' = total(`invar'), by(`byvar')
    egen `count_invar' = count('invar'), by('byvar') 
    gen `outvar' = (`tot_invar' - `invar') ///
    / (`count_invar' - 1) 
end 

Con el programa podemos escribir los bloques de código anteriores como:

* Caso 1: a nivel de región

consumo_papitas_resto, invar(pc_papitas) ///
outvar(consumo_papitas_resto_pc) byvar(region)

* Caso 2: a nivel de área metropolitana

consumo_papitas_resto, invar(pc_papitas)  ///
outvar(consumo_papitas_restometro_pc) byvar(metroarea)

Hemos escrito la función de forma totalmente general. Podemos cambiar el nivel de agregación sin inducir errores por ir copiando y pegando códigos, además automatizamos un comando y evitamos repetición.

2.2.10 Crear códigos autoexplicativos que complementen a la documentación

  • No escribas documentación que no vas a mantener.
  • Lo mejor es que los códigos sean autoexplicativos.
  • Veamos un ejemplo. Imaginemos que queremos estimar una elasticidad de demanda para hacer un análisis de bienestar.
* Elasticidad = Cambio porcentual en la cantidad / Cambio Porcentual en precio
* Elasticidad = -0,4 / 0,2 = -2
* Mirar Informe 1, Tabla 2A.
    calcular_perdida_bienestar, elasticidad(3)
  • Problema: código contradice comentario. Cuando tenemos dos fuentes o más fuentes que informan sobre el mismo objeto, es probable que estas se puedan contradecir. El problema de inconsistencia interna es especialmente importante para documentación, comentarios, notas, etc.

  • Para evitar este problema es necesario mantener los comentarios al día tal como se hace con los códigos.

  • Hacer esto es costoso. Mantener un código extenso al mismo tiempo que una larga documentación no es sencillo.

  • Dada esta restricción, es importante escribir códigos que sean claros sin la necesidad de escribir comentarios extensos.

  • Volviendo al ejemplo. ¿Cómo le decimos al lector del código debe tener una elasticidad de 2 y no de 3?

Ejemplo de un código auto-explicativo:

* Mirar Informe 1: Tabla 2A. 
  local cambio_porcentual_cantidad = -0,4
  local cambio_porcentual_precio = 0,2 
  local elasticidad = `cambio_porcentual_cantidad' ///
  / `cambio_porcentual_precio'
  calcular_perdida_bienestar, elasticidad(`elasticidad') 

Menos comentarios que el anterior. Sin números mágicos, los parámetros están definidos por variables locales, en vez de imputados directamente. Este código es más informativo y es internamente consistente dado que no puedo cambiar algunos de los parámetros sin modificar el resultado. Comentarios sirven en su justa medida: es imposible desprender del mismo código sin saber la tabla.

2.2.10.1 Pensar siempre en la unidad de observación e identificar los ID que identifican únicamente a la unidad

de observación

  • ID permiten saber la unidad de observación (hogar, empresas, lugares, hogar-año, empresa-mes-lugar).
  • Conocer ID únicos es esencial para entender los datos. Indican qué es lo que describen los datos.
  • También nos sirven para entender cómo juntar estos datos con otras fuentes de información.
  • Dos reglas que siempre tener en cuenta:
    • No tienen que existir observaciones duplicadas que tengan el mismo ID único.
    • Los ID no pueden tener missings.
  • Una forma de verificar estos dos hechos es utilizando el comando isid. Este comando chequea si las variables especificadas identifican únicamente a las observaciones. Si esto no ocurre arrojará el siguiente mensaje:
variable does not uniquely identify the observations

Si encuentro plausible que alguna variable tenga missing puedo colocar la opción missok.

2.2.11 No ser repetitivo

Hemos hablado de evitar ser repetitivo. ¿Cuándo hacerlo? Repetir en una operación simple con dos categorías es razonable.

xtile decil_ing_ga = ing if grupo=="A", nq(10)
xtile decil_ing_gb = ing if grupo=="B", nq(10)

Si tengo que operar 15 veces, mejor hacerlo iterativamente:

forvalues y = 2001/2015 {
    xtile decil_ing_`y' = ing if año == `y', nq(10)
}

Si involucra múltiples operaciones. A pesar de que solo existan dos categorías, es mejor hacerlo iterativo.

foreach g in "A" "B" {
    assert ingreso >= 0 if grupo == "`g'"
    xtile decil_ingreso_`g' = ingreso /// 
    if grupo=="`g'" & ingreso > 0, nq(10)   
    replace decil_ingreso_`g' = 0 /// 
    if grupo=="`g'" & ingreso == 0
    label var decil_ingreso_`g' "Deciles de ingreso"
}

¿Cómo evitar ser repetitivo?

  • Cuando necesites cambiar solo una cosa en el código utilizar un loop. foreach y forvalues iteran por el mismo código múltiples veces, cambiando el valor de una variable local cada vez.
  • Cuando necesites cambiar múltiples cosas dentro de un código, define un programa dentro del do-file utilizando program. De este modo tú podrás especificar más de un argumento.
  • Cuando necesites repetir un código en múltiples do-files, pueden definir un programa en un ado-file, guardarlo y llamarlo cuando lo necesites. Es importante que el código agregue automáticamente la ruta en donde se encuentran guardados estos programas.

Algunas ayudas:

  • Cuando algunas líneas de código necesiten cambiar entre repeticiones utilizar if/else y forvalues. Estos iteran por el mismo código múltiples veces, cambiando el valor de una variable local cada vez.
  • Cuando definas programas dentro de un do-file, agrega una línea que diga cap program drop <program_name> antes de program define. Automáticamente se eliminará y redefinirá el programa cada vez que ejecutes el código.

2.2.12 Mensajes finales sobre estilo de codificación

  • Haz las cosas lo más simples posibles para ti (y tu equipo) de hoy y del futuro.
  • No confíes tanto en ti de hoy y menos en el del futuro. Es mejor programar defensivamente.
  • Ser consistente en formato, estilo, organización y nombres. Sigue estrategias.
  • Reducir en lo posible pegado de códigos y repetición innecesaria.
  • Testear regularmente.
  • Documentar a menudo, estratégicamente, pero mínimamente.

2.3 Organización de un proyecto en Stata

2.3.1 Flujo de trabajo en Stata

Hasta el momento uno de los mayores mensajes es adoptar un sistema de organización, compartirlo en el equipo y adherirse a él. Este debe incluir:

  1. Estructuras de directorio.
  2. Estilo de codificación.
  3. Convenciones para escribir nombres.
  4. Convenciones para exportar datos.

Hemos visto en detalle (2) y (3). Algunas cosas de (4) (más detalles en otro capítulo). En esta sección nos enfocaremos en (1). Esta sección se basa en una de las guías de Asjad Nqvi. Muy buenos recursos. Muy recomendado. También revisaremos algunos elementos de ().

  • Un proyecto de análisis de datos contempla: planificar el trabajo, documentar las actividades, crear y verificar variables, generar y presentar análisis estadísticos, replicar resultados y archivar.
  • Todo lo anterior es a lo que nos referiremos como flujo de trabajo.
  • Un buen flujo de trabajo es esencial para que tú y tus colaboradores(as) y los interesados en tu trabajo puedan replicarlo.
  • Replicar es clave para generar información confiable y correcta.

La administración del flujo de trabajo se hace al inicio de un proyecto. No al final. No hacerlo así tiene costos en tiempo y posiblemente induzca errores no forzados. Veremos algunos aspectos relacionados con la administración de datos y scripts. Nuevamente, más que reglas a seguir, lo presentado aquí son una serie de buenas prácticas que pueden ayudar a mejorar la gestión del trabajo con Stata. La idea de esto es que finalmente podamos dedicarle más y mejor tiempo al análisis de datos. * Nuevamente, tener un flujo de trabajo es clave, incluso los mayores expertos en estos temas tienen problemas con esto. Por ejemplo, en el prólogo de Long and Long (2009)

When I started, I thought my workflow was very good and that it was simply a matter of recording what I did” As writing proceeded (this book), I discovered gaps, inefficiencies, and inconsistencies in what I did. Sometimes these involved procedures that I knew were awkward, but where “I never took the time to find a better approach”. Some problems were due to oversights where I had not realized the consequences of the things I did or failed to do.

2.3.2 Organización de archivos y carpetas

  • Algunos problemas que son recurrentes:
    • Tener múltiples versiones de un archivo y no saber cuál es cuál.
    • No poder encontrar un archivo y pensar que lo has borrado.
    • Tu equipo (y tú) no saben cuál es el informe final. Hay dos archivos que con el nombre archivo final, pero con distinto contenido.

Para evitar los problemas anteriores es importante diseñar la estructura de la carpeta de trabajo y comprometerse a seguir una alerta.

2.3.2.1 Carpetas

  • Todo se guarda en carpetas. TODO.

  • Estas deben seguir un orden lógico e intuitivo. Como consejo. Colocar números en la carpeta. Al ordenar las carpetas seguirán este orden y no el alfabético.

  • No tener espacios en el nombre de las carpetas.

  • Nunca utilizar (-) entre nombres de una carpeta. Utilizar (_).

  • Evitar nombrar las carpetas con mayúsculas.

  • Siempre escribir un README.txt. Puede ser tedioso, pero muy necesario. Corto, informativo, que explique el flujo de trabajo y las carpetas. Sugerencia: colocar las rutas.

  • En esta figura se ve la idea de cómo debería estructurarse las carpetas de un proyecto pequeño

  • Lo mismo, pero para un proyecto grande

  • Lo mismo, pero presentado de otra forma:

  • En la medida que sus carpetas se parezcan más a estas, mucho mejor.

  • Es importante generar dos tipos de carpetas para los resultados trabajo y otras que diga compartir.

  • trabajo guarda todos los resultados (ej. tablas, gráficos, documentos) que están siendo trabajados.

  • compartir guarda resultados terminados y listos para compartir en alguna etapa del proyecto. Por ejemplo, cuando se quieran compartir resultados intermedios del proyecto.

  • Dos reglas:

    • Resultados se comparten solo después que los archivos que lo generan pasen a la carpeta compartir.
    • Una vez traspasados a la carpeta compartir. No se modifican. Incluso cuando puedan existir errores.

Ayuda a garantizar que los resultados que se comparten se puedan replicar. Si encuentras errores o decides cambiar algo no cambies los ya posteados. Genera nuevos. Esto también ayuda a la replicabilidad: permite saber qué cambios existieron durante un proyecto.

Un directorio de trabajo estructurado es especialmente importante para proyectos colaborativos donde todo se puede desordenar más fácilmente. Dos directorios son sugeridos cuando se trabaja de forma colaborativa: correo y otras que diga privados. correo guarda intercambios entre colaboradoras mientras que privados guarda el trabajo propio de cada colaborador(a). Otras carpetas

que pueden complementar trabajo son porhacer que sea una carpeta que sirva como una lista de tareas poraprender. En cualquier caso, estas carpetas pueden ser parte de privados.

Cuando se tengan versiones se pueden utilizar dos modos:

  • v1, v2, v3, etc.
  • Fechas. Si se utilizan estas escribirlo en año/mes/día. De esta forma se ordenará automáticamente desde el último al primero.

Cuando versiones anteriores no te sean útiles. Bórralas! No acumules archivos y códigos porque sí. Si por alguna razón deseas dejarlos (ej. necesidad de respaldar lo hecho). Genera una carpeta temporal. Esta puede estar en tu versión personal del proyecto, pero no en el archivo final.

2.3.3 Master do-files

  • Un Master do-file es un do-file que ejecuta todos los códigos relevantes para el proyecto.
  • Se basa en la idea de que diferentes do-files se enfocan en diferentes tareas o subtareas. No es buena práctica tener un solo código enorme que haga todo el proceso.
  • Es importante separar tanto todos los do-files (incluyendo el master) en secciones y subsecciones. Por ejemplo: Preámbulo, cargar datos, generar variables, figura I, Tabla 3, etc.
  • Crear master_do.files cada proyecto o subproyecto debe tener un archivo maestro que ejecute todos los códigos de inicio a fin y genere todos los resultados.
  • Cada vez que se termine un proyecto o se obtenga algún resultado es importante ejecutar el master_do.files.

Ejemplo de master do-file:

  *** Información del proyecto aquí ***
  *** Información sobre directorios ***
  *** Ejecutar códigos ***
  * Generación de datos
  do ./dofiles/01_datos_v11.do 
  do ./dofiles/02_merge_v2.do 
  * Generación de tablas
  do ./dofiles/03_tablas_v4.do 
  * Estimación principal
  do ./dofiles/04_estimaciones_v11.do 
  * Figuras principales
  do ./dofiles/05_graficos_v11.do 

2.3.4 Rutas de las carpetas:

  • Es importante tener una carpeta principal y referenciar todas las rutas a esa dirección.
  • Utilizar siempre / no \. Puede causar problemas según el sistema operativo que utilices.
  • Utilizar macros para nombrar a las carpetas. Que estos nombres tengan sentido y se relacionen con el flujo de trabajo.
  • Recordar que una variable local guarda información temporalmente mientras que global guarda información permanentemente. Esto último hace de los global algo no recomendable de utilizar constantemente. No obstante, es útil para los directorios.
   *** Nota 1: Reemplazar esta ruta ***
   global miproyecto "C://Program Files/Dropbox/miproyecto/"
   
   *** Nota 2: Directorios de subcarpetas ***
   clear
   global datosbrutos "$miproyecto/datos/brutos"
   cd "$datosbrutos"
   use datos1.dta, replace 

2.3.5 Utilizar algún auxiliar de generación de código: Sublime Text

Esta sección está basada en la página web de Alvaro Carril.

2.3.5.1 ¿Qué es Sublime?

  • Sublime Text es un editor de códigos gratuito. Este editor permite compilar códigos de distintos lenguajes de programación tales como Stata, Python, R, , entre muchos otros.

  • Tiene algunas herramientas que facilitan el trabajo de programación tales como atajos (shortcuts) o multicolumnas. Veremos varias en esta sección. Es muy útil cuando tienes un proyecto grande con códigos de distintos tipos de lenguaje. Instalar Sublime

  • Dirígete a sublimetext.com. Descarga e instala Sublime Text 4 (ST4) para tu sistema operativo.

  • Es esencial que también instales Package Control, que te permite añadir y eliminar fácilmente complementos adicionales. Si está bien instalado, debiese aparecer en preferences.

  • Para instalar hay que entrar a sublime, apretar ctrl + shift + p.

  • Tipear Install Package Control y presionar enter.

2.3.5.2 Ejecutar Stata desde Sublime

Para Windows

  • Instalar StataEditor: En ST4 apreta ctrl+shift+p. Escriba install y presione Enter. Ahora busque StataEditor y haga clic en él para instalarlo.
  • Instale Pywin32: repita el proceso anterior pero instalando el complemento Pywin32.

Configure StataEditor:

  • En ST4 vaya a Preferences -> Package Settings -> StataEditor -> Settings - Users
  • En este archivo en blanco debe escribir la ruta de su ejecutable de Stata y la versión que posee.
  • Mi archivo de configuración en Windows se ve así:
{
  "stata_path": "C:/Program Files/Stata17/StataMP-64.exe",
   "stata_version": 17,
}

Registre la biblioteca de automatización de Stata:

  • Vaya al ejecutable de Stata del que ha copiado la ruta (por ejemplo, StataMP-64.exe).
  • Cree un acceso directo en su escritorio.
  • Ahora haga clic con el botón derecho en este nuevo acceso directo y seleccione “Propiedades”.
  • En el campo “Destino”, añada /Registro al final (con un espacio precedente). En mi caso es:
"C:\Program Files\Stata17\StataMP-64.exe" /Register

Aplicar y aceptar los cambios. Apretar sobre el acceso directo el clic derecho y ejecutar como administrador. ¡Y listo!

Para Mac

  • Para instalar el Editor Mejorado de Stata en ST4, inicie la paleta de comandos con Cmd+shift+p, escriba “install” y presione Enter.
  • Ahora busque Stata Improved Editor y haga clic en él para instalarlo.
  • Reinicie ST4 y listo!

Autoguardado

  • Sublime permite auto-guardar los códigos.
  • De esta forma no hay que preocuparse en casos de que no hayas respaldado tu código.
  • Para esto hay que escribir vamos a instalar el paquete autosave y adicionalmente vamos a agregar a “preferencias”:
"save_on_focus_lost": true.

References

Chang, Andrew C, and Phillip Li. 2015. “Is Economics Research Replicable? Sixty Published Papers from Thirteen Journals Say’usually Not’.”
Christensen, Garret, and Edward Miguel. 2018. “Transparency, Reproducibility, and the Credibility of Economics Research.” Journal of Economic Literature 56 (3): 920–80.
Gentzkow, Matthew, and Jesse M Shapiro. 2014. “Code and Data for the Social Sciences: A Practitioner’s Guide.” Chicago, IL: University of Chicago.
Long, J Scott, and J Scott Long. 2009. The Workflow of Data Analysis Using Stata. Stata Press College Station, TX.