Apuntes Final DCA

Versión en PDF (recomendada): https://ls.ecomaikgolf.com/apuntes-ua/dca/apuntes.pdf

1. Estructura de un equipo de desarrollo

1.1. Ortogonalidad

Ortogonalidad: número de programadores afectados al realizar un cambio en el proyecto. Depende del proyecto, del diseño y de las personas con las que contamos.

\(\uparrow\) programadores = \(\downarrow\) ortogonalidad

Para tener un sistema ortogonal hay que separar la infraestructura de la aplicación, y cada componente de la infraestructura que lo gestione un subequipo.

1.2. Estructuras

1.2.1. Jerárquicas

  • Programador jefe (planifica, coordina, revisa…)
  • Personal técnico (hacen análisis y desarrollo)
  • Ingeniero de apoyo (ayudan al jefe y puede sustituirle)

Un bibliotecario de software cataloga e indexa los módulos (o objetos reutilizables)

1.2.2. Descentralizado democrático

No tiene jefe permanente, hay coordinadores a corto plazo.

Hay comunicación horizontal

1.2.3. Descentralizado Controlado

Tiene un jefe definido para que coordina tareas y jefes secundarios sobre subtareas.

La solución de tareas es en grupo, la implementación se divide entre subgrupos por el jefe.

La comunicación entre subgrupos es horizontal y en la jerarquía es vertical.

1.2.4. Centralizado Controlado

El jefe resuelve problemas a alto nivel y coordina

La comunicación es vertical

1.3. Organización de equipos

  • Paradigma cerrado: similar a centralizado controlado
  • Paradigma aleatorio: de manera libre mediante iniciativa individual (innovación)
  • Paradigma abierto: mezcla de cerrado + aleatorio (muy buena comunicación) (problemas complejos)
  • Paradigma sincronizado: partes del problema sirven para organizar (poca comunicación entre equipos

1.4. Dictador Benevolente de por vida (BDFL)

  • Linus Torvalds: Linux
  • Guido van Rossum: Python
  • Larry Wall: Perl
  • Alexandre Julliard: Wine

No tiene por qué ser vitalicio

2. Despliegue e Instalación

2.1. Equipos de desarrollo

  • Uniformidad a la hora de que los equipos se comuniquen de cara al exterior
  • Evitar repeticiones
  • análisis, diseño, codificación y testeo no se debe hacer de forma aislada
  • Automatizarlo todo, da consistencia al trabajo

2.2. Rama máster/trunk

No tiene que ver con SCV

La rama representa la línea principal de desarrollo de un proyecto software antes de ser distribuido.

  • Gestión por solo una persona
  • Deben aceptarse
    • Añadidos
    • Borrados
    • Modificaciones

Contiene código estable e inestable, el integrador es el que decide cuando es estable.

Siempre tiene las últimas modificaciones, puede no funcionar bien.

  • El concepto de la rama máster puede aplicarse a subproyectos del proyecto también

Si tenemos la versión estable v1.0.0 podemos ir teniendo nuevas propuestas en desarrollo o trunk o master.

2.3. Número de etiquetas de versión

Dan información útil para usuarios y desarrolladores.

En la mayoría suelen ser números pero pueden ser letras también o fechas o números de compilación.

\((mayor.menor.micro)\)

  • menor par: rama estable
  • menor impar: rama inestable

3. Bugtracking

Un sistema de seguimiento de fallos es una aplicación que ayuda a los programadores a llevar un registro de fallos.

Algunos sistemas d ebugtracking están diseñados para trabajar con el sistema de control de versiones.

Es conveniente fijar tipos de error predefinidos para facilitárselos al usuario.

quizás más tipos de fallos le hagan echarse atrás a la hora de reportar un fallo

3.1. Usos de bugtracking

  • Conocer que avisos son reales y cuáles no
  • Ver el estado de tratamiento de un error en un instante
  • Ver como etán respondiendo los desarrolladores a los avisos

3.2. Servicios de código

Github, etc integran su propio sistema de seguimiento de fallos.

4. Sistemas de paquetes

Debemos evitar instalaciones tipo Windows:

  • Desconoce componentes ya instalados
  • No tiene en cuenta dependencias
  • Permite sobreescritura de archivos ya instalados
  • Alternativa: Windows Installer

4.1. TAR/TGZ/TBZ/TXZ

Es el Tape ARchiver, ``junta’’ archivos y directorios en uno «por decir». Soporta almacenar fechas de archivo, permisos, propietario y tiene soporte para enlaces duros y simbólicos.

NO realiza compresión de ficheros.

Tiene carencias para usarse como empaquetado para sofrware, no puede gestionar las dependencias del software, ejecutar acciones, etc.

4.1.1. Compresión

  • gzip: -z
  • bzip2: -j
  • xz: -J

4.2. DEB

Es un fichero ar que contiene:

  • debian-binary (versión del formato .deb usado)
  • control.tar.gz (metainformación del paquete)
  • data.tar (el paquete)

4.2.1. Crear un DEB manualmente

./debian
./debian/DEBIAN
./debian/DEBIAN/control
./debian/usr
./debian/usr/bin
./debian/usr/bin/binario
fakeroot dpkg -b ./debian foo.deb

4.2.2. Crear un DEB con dh-make

dh_make hace uso de los programas que se encuentran en debhelper.

Partimos de un .tgz con el código y un makefile con el objetivo install que lo instala en la ruta que parte desde $(DESTDIR)

  • Descomprimimos el .tgz, entramos en su carpeta y ejecutamos
dh_make -s -e mail@provider.com -f
   ../helloworlddca-1.0.tar.gz
  • Esto genera los archivos:
changelog        docs
init.d.ex        menu.ex
compat           helloworlddca.cron.d.ex
manpage.1.ex     postinst.ex
control          helloworlddca.default.ex
manpage.sgml.ex  postrm.ex
copyright        helloworlddca.doc-base.EX
manpage.xml.ex   preinst.ex
source           watch.ex
prem-ex          README.Debian
README.source    rules

Podemos modificar los archivos y los post/pre inst y rm.

Luego construimos con:

dpkg-buildpackage -rfakeroot -us -uc

Para actualizar, creamos una nueva entrada en debian/changelog (o usamos dhc) y regeneramos el .deb

Para instalar el .deb:

dpkg -i .deb
apt install ./.deb

4.3. RPM

Es similar a .deb usado en RedHat, Fedora, Suse…

4.4. alien

Se ejecuta con administrador

Permite convertir entre formatos

  deb tgz rpm
deb   -t -r
tgz -d   -r
rpm -d -t  
sudo alien -[t,d,r] ../.deb

Además tiene la opción -c para intentar convertir los scripts que se ejecutan

5. Compilación de grandes proyectos

5.1. Make

Make es una herramienta de construcción de proyectos basada en marcas de tiempo

  • -k continua ejecutando aún con errores
  • -d printea lo que hace
  • podemos cambiar variables de entorno make CC=clang

5.1.1. makefile

Fichero ASCII

Lo componen objetivos, dependencias y órdenes.

Hay objetivos especiales como .PHONY que sirven para indicar que un objetivo no es el nombre de un fichero.

Un separador : ignora dos objetivos llamados iguales. Un separador :: evalúa los dos objetivos. No podemos mezclar ambos separadores.

  • ~\(?\) representa la lista de dependencias del objetivo que son más jóvenes que el objetivo actual
  • ~\(^\) representa la lista de dependencias
  • ~\(@\) representa el objetivo actual

    Objetivos especiales:

  • all
  • clean
  • dist
  • install
  • uninstall

5.1.2. Make paralelo

Podemos ejecutar make en paralelo con -jN. -j puede valer lo que quiera, se recomienda número de hilos \(+2\)

El ejecutar make en paralelo suele descubrir fallos a la hora de especificar las dependencias.

5.1.3. Make recursivo vs No recursivo

make permite llamadas recursivas, por lo que si teneos un proyecto grande podemos tener sub-makefiles con scripts de compilación y que make les llame. A esto se le conoce como make recursivo.

Hay desarrolladores que descartan los makes más recursivos, pueden ser más lentos.

5.2. ccache

Solo funciona con gcc o similar

Se trata de una herramienta que cachea los resultados del compilador. Se guardan en /.ccache/ en una tabla hash con MD4. Soporta:

  • C/C++
  • Objective C/C++

    Funcionalidades:

    • Estadísticas
    • Soporta enlaces duros para evitar copias
    • Opcionalmente comprime la caché
    • Cachea compilaciones con warnings

      Algunas opciones de gcc no están soportadas, si sucede ccache lo detecta e invoca al compilador real.

5.2.1. Modos de funcionamiento

  • directo (cachea preprocesado y source)
  • preprocesador (para ficheros preprocesado)
  • depend mode (cachea preprocesado + source)

5.3. distcc

Está pensado para gcc pero funciona con los compiladores de intel y oracle. Es importante tener la misma versión del compilador el todas las máquinas, por la ABI.

Se compone de distcc (cliente) y distccd (servidor)

Compila:

  • C/C++
  • Objective C/C++

    Funciona sobre TCP y sobre SSH.

    Se ejecuta con el -j N de make, como regla sencilla usamos el doble de CPUs de la red

5.3.1. Modos de funcionamiento

  • Sencillo (preprocesa y envía el fuente a compilar)
  • Bombeo (envía fuente y headers)

El bombeo puede ser unas 10 veces más rápido

5.3.2. Uso

distccd --daemon --allow IP-permitida
export DISTCC_HOSTS="localhost IP"
make -j8 CC=distcc

También podemos configurar los hosts de la red en archivos de configuración.

5.3.3. distcc + ccache

  • Ejecutar ccache antes que distcc
  • No usar distcc en modo bombeo para ejecutar el preprocesador solo 1 vez
export CCACHE_PREFIX="distcc"
CC="ccache gcc"

6. Configuración y adaptación automática de proyectos

Cualquier proyecto debe crearse teniendo en mente:

  • Su portabilidad
  • La facilidad de reconstruirlo cada vez que sea necesario
  • La facilidad de construirlo en un sistema diferente al de desarrollo

Si es fácil de reconstruir evitamos posibles situaciones de error al ser recompilado.

Las herramientas que permiten configurar y adaptar la construcción de un proyecto hacen tests y chequeos antes de proceder a la compilación. Según los resultados de estos tests podemos adaptar el proceso de compilación.

Requisitos de un sistema de configuración automática:

  • Buscar los programas necesitados para compilar
  • Out of source builds
  • Poder generar archivos nuevos necesitados para la construcción del proyecto
  • Permitir seleccionar componentes opcionales
  • Generar proyectos/soluciones/makefiles para que el SO destino pueda construir
  • Permitir cambios entre modelo de generación de archivos binarios estáticos y dinámicos
  • Tener en cuenta las dependencias entre ficheros

6.1. Autotools

Autotools consta de tres componentes: autoconf, automake y libtool.

Funciona en los tres SO tipo unix y en windows bajo cygwin

Para funcionar no necesita tener instalado autotools, genera guiones de shell Posix compatible.

Comandos imprescindibles para autoconf:

autoscan autoreconf autoupdate

6.1.1. Funcionamiento

IJepbU.png

  1. configure.ac -> autoconf -> configure

Automake es opcional, podemos escribir el Makefile.in a mano

Creamos un Makefile.am (o Makefile.in) en el directorio raiz del proyecto y otro por cada subdirectorio del proyecto (si lo queremos recursivo el make).

6.1.2. Makefile.am

En automake interviene el concepto de primarios:

# Makefile.am
bin_PROGRAMS = hw
hw_SOURCES = hw.cc main.cc
hw_LDADD =
hw_CFLAGS =
hw_CXXFLAGS =

Si tuvieramos varios subdirectorios con Makefile.am en ellos ponemos:

SUBDIRS = src app gui

Al usar automake tenemos que poner en el configure.ac el macro AM_INIT_AUTOMAKE.

6.1.3. Autoconf + Automake

Ejecutar make antes de configure comprueba si se ha configurado, si no lo configura.

autoscan
# Edita configure.scan -> configure.ac
touch NEWS README
touch AUTHORS ChangeLog
autoreconf --force --install # (1)
# (1) aclocal + autoconf + autoheader + automake
./configure
make

6.1.4. Automake no recursivo

automake soporta compilar el proyecto de forma no recursiva, poniendo en los sources el path del fuente y teniendo solo un Makefile.am

6.1.5. Configuraciones de automake

  • no-dist-gzip (no comprime con gzip)
  • dist-xz (comprime con xz)
  • foreign (no autores NEWS etc)

6.2. CMake

Comienza a desarrollarse en 1999 como parte del Insight Toolkit.

Se comporta como Autoconf y Automake juntos

Dispone de herramientas como CPack CTest y CDash

6.2.1. Generadores

cmake no solo genera makefiles, entiende el concepto de generador:

VpEUZY.png

Seleccionas un generador con cmake -G "gen", los buscamos con man cmake-generators man cmake o cmake --help

6.2.2. Encontrar un paquete

find_pacakge(name)
# Luego definido:
name_FOUND
name_INCLUDE_DIR
name_LIBRARIES
name_LINK_DIRECTORIES

6.2.3. Instalación

Soporta la instalación de:

  • Objetivos creados al compilar
  • Ficheros en general
  • Directorios completos

6.2.4. Generar config.h

configure_file(srcdir bindir)

6.2.5. Gráficos de dependencias

cmake --graphviz=deps.dot .

6.2.6. Interfaces

CLI, curses y GUI

6.3. Meson

Muy nuevo, escrito en python3 para Linux/OSX/Windows.

Se configura con un meson.build

Usa ninja por defecto (hay vs o xcode), no tiene soporte para makefiles

Solo permite out of source

6.3.1. Uso

meson build; cd build; ninja
# O simplemente
meson build; ninja -C build

NO es necesario ejecutar meson build si cambiamos nuestros archivos meson.build, esto generará un error.

7. Generación y paso de tests

7.1. Propósito

El propósito es demostrar que en nuestro software existen fallos, NO demostrar su ausencia

Comprobar un programa consiste en ver si su comportamiento es correcto para cualquier posible entrada (esto es imposible, necesitamos heurísticas). A este conjunto de entradas es lo que se le llama test suite, hemos de procurar que no tarden mucho tiempo en ejecutarse.

Para obtener una buena test suite es recomendable particionar un conjunto de datos de entrada en subcojuntos, de manera que cada elemento del conjunto original pertenezca exactamente a uno de estos subconjuntos. Esto es imposible así que hemos de emplear heurísticas, como usar una entrada de cada uno de los subconjuntos.

7.2. Tipos de tests

7.2.1. BlackBox (Caja Negra)

  • Se crean sin mirar el código a testear, se basan en la especificación.
  • Los programadores del código y los tests pueden ser distintos.
  • Se mide el porcentaje de especificación testeado (Specification coverage).

7.2.2. WhiteBox/GlassBox (Caja Blanca)

  • Se tiene el código a testear (nos fijamos en las sentencias)
  • Complementan a BlackBox, son más fáciles de crear
  • Son más difíciles de mantener si se cambia el código
  • Se mide el Instruction coverage y el Branch coverage.
  • Incluye el concepto de cobertura de un test

7.3. Qué testear

  • Tests unitarios
  • Tests de integración (integración de módulos)
  • Tests de sistema (sistema al completo)
  • Tests de rendimiento
  • Tests de usabilidad

7.4. Cómo testear

  • Tests de regresión (no debe estropear lo que funcionaba)
  • Tests de datos (datos reales y sintéticos)
  • Tests de UI
  • Tests de los tests

7.5. xUnit

Es el término empleado para describir una serie de herramientas de test que se comportan de manera similar. Surge de SUnit para Smalltalk, posteriormente se portó a JUnit, .NET NUnit, C++ cxxtest, etc.

7.5.1. Conceptos generales xUnit

  • Test runner
  • Test case
  • Test fixtures
  • Test suites
  • Test execution

7.6. cxxtest

  • Es un entorno de testeo tipo xUnit.
  • Soporta el descubrimiento de tests, no es necesario registrarlos
  • Se definen en los .h, cxxtestgen genera los .c

7.7. boost::test

  • Puede convertirse en el marco de test estandar para C++
  • Los tests van en un .cpp

7.8. GLib.Test

  • Librería GLib pensada para desarrollar en C
  • Adaptaciones de GLib nos pueden dar acceso a otros lenguajes a esta librería
  • Permite crear test individuales y test suites

7.9. Integración de paso de test

7.9.1. cmake

Lo integramos con CTest, enable_testing() y añadimos los test con add_test(...).

7.9.2. autotools

Introducimo s check_PROGRAMA.

8. Diseño por Contrato

El término fue usado por primera vez por Bertrand Meyer al crear el lenguaje de programación Eiffel, también se registró comercialmente en término DbC.

Está basado en la verificación y especificación formal de código, también en la derivación de programas.o

8.1. Elementos del contrato

8.1.1. Precondiciones

  • Método/Función puede tener varias
  • Es una propiedad que un método/función impone a todos sus clientes
  • Para los clientes es una obligación, para el método llamado es lo que ``espera’’
  • Útiles depurando

8.1.2. Postcondiciones

  • Representa lo que se obtendrá del método (si se han cumplido las precondiciones)
  • Útiles depurando

8.1.3. Invariantes de clase

  • Son propiedades lógicas asociadas a una clase
  • Se deben cumplir nada más crear un objeto de la clase y antes y después de ejecutar cada método de la mismao

8.2. Lenguajes

  Precondiciones Postcondiciones Invariantes
Eiffel X X X
D X X X
Vala X X  
C/C++      

9. Internacionalización (I18N) y Localización (L10N)

9.1. locale

Es lo que hace que funcione la internacionalización. Consta de una serie de parámetros culturales escritos en un archivo en una variante de un idioma hablado en un territorio.

9.1.1. Parámetros:

  • Juego de caracteres
  • Código del lenguaje
  • Representación de fecha y hora
  • Números
  • Moneda
  • Direcciones de teléfono
  • Medidas

    Formato: idioma[_territorio][.codeset][@modifier]

    La parte del idioma es iso 639 la del territorio iso 3166 y archivo de datos iso 15924

9.2. Internacionalización vs Localización

Internacionalizar es preparar un proyecto para que soporte multitud de idiomas, localización es tomar dicho proyecto internacionalizado y proporcionarle la suficiente información para que se adapte al idioma y configuración del usuario.

9.3. Gettext en C++

9.3.1. Trabajo en C++

Incluímos libintl.h

Ponemos

setlocale (LC_MESSAGES, "");
bindtextdomain (GETTEXT_PACKAGE, localedir);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);

Marcamos las cadenas.

xgettext puede con -a sacar todas las cadenas aunque no estén marcadas

9.3.2. Trabajo con gettext

Gettext es un framework y un conjunto de herramientas que permiten internacionalizar un proyecto.

Creamos un directorio «po» en la raíz del proyecto. Extraemos las cadenas:

xgettext -d intlapp -o po/intlapp.pot -s ./src/app.vala

Editamos el .pot y lo cambiamos a .po traducido. También podríamos cambiar el nombre del fichero con:

msginit -l es -o po/ca.po -i po/intlapp.pot

Con los cambios hechos compilamos a .mo:

msgfmt -c -v -o intlapp.mo ca.po
.pot -> .po -> .mo

Los ficheros .mo residen en:

/usr/share/locale/idioma/LC_MESSAGES/app.mo

9.3.3. Mantenimiento de .po

Extraemos .pot como al principio

Unimos con:

msgmerge -s -U po/catalan.po po/intlapp.pot

10. Sistemas de Control de Versiones de última generación

Se trata de un software que nos permite conocer la información de las modificaciones que vamos haciendo a nuestro software.

Todo lo que nos da podemos hacerlo manualmente.

10.1. Conceptos generales

Repositorio: Es la copia maestra

Copia de trabajo: La copia de los ficheros del proyecto que podemos modificar. Cada desarrollador tiene la suya propia.

Check out/Clone: Obtener una copia de trabajo desde el repositorio

Check in/Commit: La acción para llevar los cambios hechos en la copia de trabajo a la copia local del repositorio.

Push: Traslada contenidos de copia local a copia maestra

Update/Pull/Fetch+Merge/Rebase: Actualiza nuestra copia local del repositorio a partir de la copia maestra, además actualiza la copia de trabajo.

Conflicto: Cuando 2 desarrolladores hacen un commit con cambios en la misma región del mismo fichero.

Rama: Representa una línea de evolución de nuestro software, una es especial, master.

10.2. Tipos de SCV

10.2.1. Por la forma de almacenar contenidos

  • Centralizados: (Único repositorio compartido por todos) CVS, Subversion
  • Distribuidos: (Cada usuario tiene su propio repositorio) git, mercurial, bazaar, monotone

10.2.2. Por la forma de modificar contenidos de la copia local

  • Colaborativos: (Editar archivos a la vez) git, mercurial
  • Exclusivos: (Editar archivos mutex) RCS, SourceSafe

10.3. Tipos de Ramas

  • Largo recorrido
  • Ramas puntuales

10.4. Formas de integrar una rama en otra

  • Merge (mezcla)

    master:   A--B--C
    topic:    A--B--C
                     \
                      X--Y--Z         1
    
    El tiempo pasa: A--B--C--D--E--F  2
                           \
                            X--Y--Z
    
    mezcla: A--B--C--D--E--F--M       3
                   \         /
                     X--Y--Z
    
  • Rebase (rebasamiento)

    master:   A--B--C
    
    topic:    A--B--C
                     \
                      X--Y--Z          1
    
    El tiempo pasa: A--B--C--D--E--F   2
                           \
                            X--Y--Z
    
    mezcla: A--B--C--D--E--F           3
                            \
                             X'--Y'--Z'
    

10.5. Git

Linux usaba BitKeeper hasta 2005 hasta que Linus Torvalds creó Git. Gitusa SHA1 y recientemente SHA256

  • Es barato trabajar con ramas

10.5.1. Bisect

Marca commit inicial/final en el que hayamos introducido un bug entre medias y hace búsqueda binaria para encontrar el commit que lo introduce

Se está proponiendo la bisección estocástica

10.5.2. Cherry-picking

Si queremos hacer merge/rebase de un solo commit

10.5.3. Detached HEAD

Volvemos a un punto concreto del pasado. Esto crea una rama virtual donde la cabeza es ese punto concreto.

10.5.4. Etiquetas

Marcamos un commit con un texto, podemos marcar un commit concreto o el último (por default) y podemos hacer un checkout a un tag concreto.

10.5.5. Bare repos

Lo que se crea por default en un servidor git

git clone --bare ...
git init  --bare ...

10.5.6. Hooks

Guiones shell que se ejecutan automáticamente cuando hay determinadas situaciones como commits, push, etc.

Se ponen en .git/hooks.

10.5.7. Reflog

La manera de la cual git guarda información de cuando se actualizan las cabezas de rama.

Se puede usar para recuperar commits perdidos. Máximo de 30 días

10.5.8. Clean

Elimina de la copia de trabajo los archivos que no están bajo SCV

10.5.9. Fsck

Comprueba que los archivos estén bien

10.5.10. Gc

Elimina ficheros usados por git para el mantenimiento del repositorio, además optimiza.

10.5.11. Git alias y shell alias

Podemos añadir a gitconfig unas líneas para hacer alias dentro del comando de git, o también con gitconfig. También podemos ponerlos en la shell y así abreviar más.

10.6. Mercurial

  • SCV distribuido disponible en OSX, windows y Linux.
  • Surge a la vez que git
  • Escrito en python + C
  • Además de un SHA-1 associa un changeset
  • Distingue entre dos tipos de ramas:
    • Ramas con nombre
    • Clones de repositorios
  • Admite extensiones
    • Ayuda para repos git
    • Ayuda para subversion

10.7. Bazaar

  • SCV distribuido
  • Las ramas viven en su propio directorio (son directorios)