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 quedistcc
- 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
- 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:
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 territorioiso 3166
y archivo de datosiso 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)