programming-guidelines.xml
author "German Poo-Caaman~o <gpoo@gnome.org>"
Fri, 29 Feb 2008 12:05:33 -0300
changeset 7 00ea2985a116
parent 6 4e44e6123b42
permissions -rw-r--r--
Changed the encoding used to generate the files

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
    "/usr/share/sgml/docbook/dtd/xml/4.1.2/docbookx.dtd" [
<!ENTITY Emacs "<application>Emacs</application>">
<!ENTITY Vim "<application>Vim</application>">
<!ENTITY ChangeLog "<filename>ChangeLog</filename>">
]>


<article class="techreport" id="index" lang="es">

  <articleinfo>
    <title>Guía de programación de GNOME</title>

    <authorgroup>
      <author>
	<firstname>Federico</firstname>
	<surname>Mena Quintero</surname>
	<affiliation>
	  <address>
	    <email>federico@gnu.org</email>
	  </address>
	</affiliation>
      </author>
      <author>
	<firstname>Miguel</firstname>
	<surname>de Icaza</surname>
	<affiliation>
	  <address>
	    <email>miguel@kernel.org</email>
	  </address>
	</affiliation>
      </author>
      <author>
	<firstname>Morten</firstname>
	<surname>Welinder</surname>
	<affiliation>
	  <address>
	    <email>terra@diku.dk</email>
	  </address>
	</affiliation>
      </author>
      <othercredit>
	<firstname>Germ&aacute;n</firstname>
	<surname>Po&oacute; Caama&ntilde;o</surname>
	<contrib>Traducción al español</contrib>
	<affiliation>
	  <address>
	    <email>gpoo@ubiobio.cl</email>
	  </address>
	</affiliation>
      </othercredit>
      <othercredit>
	<firstname>Lucas</firstname>
	<surname>Vieites Fari&ntilde;a</surname>
	<contrib>Revisión de la traducción al español </contrib>
	<affiliation>
	  <address>
	    <email>lucas@asixinformatica.com</email>
	  </address>
	</affiliation>
      </othercredit>
      <othercredit>
	<firstname>Sergio</firstname>
	<surname>Villar Senin</surname>
	<contrib>Revisión de la traducción al español  </contrib>
	<affiliation>
	  <address>
	    <email>svillar@igalia.com</email>
	  </address>
	</affiliation>
      </othercredit>
    </authorgroup>
    <copyright>
      <year>2000</year>
      <holder>The Free Software Foundation</holder>
    </copyright>
    <copyright>
      <year>2004&mdash;2006</year>
      <holder>GNOME Foundation, respecto de la versión en español.</holder>
    </copyright>

    <abstract>
      <para>
	Este artículo contiene varías guías y sugerencias para los
	programadores de GNOME, así como ciertas políticas que
	deberían seguirse cuando se escriben programas para GNOME.
	Es un intento para que los programadores puedan aprender
	acerca del proceso de desarrollo de GNOME y su filosofía.
	GNOME es un esfuerzo de equipo, así que será útil para 
	que los programadores sepan «la forma de hacer la
	cosas».
      </para>
    </abstract>
  </articleinfo>

  <!-- Introduction -->

  <sect1 id="intro">
    <title>Introducción</title>

    <para>
	  GTK+, la biblioteca de interfaz de usuario básica de GNOME, nos
	  ha enseñado algunas lecciones importantes en el diseño de software.
	  El código de GTK+ es limpio, consistente, mantenible y tiene
	  sentido.  Tal código no sólo provoca placer al trabajar con el,
	  sino que además es un incentivo para las buenas prácticas de 
	  programación para aquellos que quieran extenderlo y modificarlo.
    </para>

    <para>
	  En este artículo intentamos presentar algunas sugerencias y 
	  lineamientos que deberías tener en cuenta cuando escribas código
	  para el proyecto GNOME.  Presentamos algunas de las políticas
	  que deben seguirse cuando se modifica el código de otras
	  personas, usando el repositorio CVS y asegurándose de que el
	  código se ajusta para ser incluído en GNOME. También 
	  presentamos información que será útil para los mantenedores
	  de paquetes.
    </para>

    <para>
	  Además de este documento, asegúrate de leer los Estándares de 
	  Programación de GNU.  Estos se encuentran disponibles en el
	  nodo info <filename>(Standards)</filename> en la documentación
	  estándar de GNU.
    </para>
  </sect1>

  <!-- The Importance of Writing Good Code -->

  <sect1 id="good-code">
    <title>La importancia de escribir buen código</title>

    <para>
	  GNOME es un proyecto de software libre muy ambicioso y, como tal,
	  está compuesto por muchos paquetes de software que son más o menos
	  independientes el uno del otro.  Mucho del trabajo en GNOME lo 
	  realizan voluntarios; programadores que vienen y se van
	  en cualquier momento y que serán capaces de dedicar
	  diferentes cantidades de tiempo al proyecto GNOME.
	  Muchas personas trabajan en software libre en su tiempo libre o
	  como un pasatiempo, así, si sus responsabilidades del &lsquo;mundo
	  real&rsquo; cambian, se verá reflejado en la cantidad de trabajo que
	  dedicarán a proyectos de software libre.
    </para>

    <para>
	  Se tarda mucho tiempo en escribir software y supone una
	  gran cantidad de trabajo. Es por esto que muchos
	  de los voluntarios de tiempo parcial no pueden comenzar 
	  grandes proyectos por sí mismos; es mucho más fácil y
	  gratificante contribuir a proyectos existentes, puesto que
	  los resultados son inmediatamente visibles y usables.
    </para>

    <para>
	  Teniendo esto en cuenta y el hecho que los programadores de
	  software libre tiene recursos escasos, concluimos que
	  para los proyectos existentes es muy importante facilitar,
	  tanto como sea posible, que otras personas puedan contribuir.
	  Una forma de hacerlo es asegurándose de que los programas
	  sean fáciles de leer, entender y modificar.
    </para>

    <para>
	  El código desordenado es difícil de leer y las personas pueden
	  perder interés si no son capaces de descifrar lo que el código
	  intenta hacer.  Además, es importante que los programadores sean
	  capaces de entender el código rápidamente, y así poder comenzar
	  a contribuir reparando fallos y extendiéndolo en un período breve
	  de tiempo.  El código fuente es una forma de comunicación, y así
	  como a alguien podría no querer leer una novela con errores
	  ortográficos y mala puntuación, los programadores deben intentar
	  escribir buen código de tal forma que sea fácil de entender y
	  modificar por otros.
    </para>

    <para>
	  Existen algunas cualidades que son importantes en un buen 
	  código y por qué son importantes para los desarrolladores
	  de software libre:

      <variablelist>
	<varlistentry>
	  <term>Limpieza</term>
	  <listitem>
	    <para>
		  Un código limpio es fácil de leer; permite a las
		  personas leerlo con un mínimo esfuerzo y así pueden
		  entenderlo más fácilmente.
	    </para>
	  </listitem>
	</varlistentry>
	<varlistentry>
	  <term>Consistencia</term>
	  <listitem>
	    <para>
		  El código consistente permite más fácilmente que las
		  personas entiendan como funciona el programa; cuando se
		  lee código consistente, subconcientemente uno se forma
		  un número de supuestos y expectativas acerca del 
		  funcionamiento del código, de esta forma es más fácil
		  y seguro realizarle modificaciones.
	    </para>
	  </listitem>
	</varlistentry>
	<varlistentry>
	  <term>Extensibilidad</term>
	  <listitem>
	    <para>
		  El código de propósito general es más fácil de reutilizar
		  y modificar que el código demasiado específico con muchos
		  supuestos escritos directamente en el código (hardcoded).
		  Cuando alguien desea agregar una nueva característica
		  a un programa, obviamente será más fácil hacerlo si el
		  código fue diseñado para ser extensible desde el inicio.
		  El código que no fue escrito de esta forma hará que las
		  personas deban implementar hacks muy feos para poder
		  añadir características.
	    </para>
	  </listitem>
	</varlistentry>
	<varlistentry>
	  <term>Corrección</term>
	  <listitem>
	    <para>
		  Finalmente, el código diseñado debe ser correcto para
		  que las personas pierdan menos tiempo preocupándose de
		  los errores y se ocupen  en extender las
		  características de un programa.  Los usuarios también
		  apreciarán un código correcto, ya que a nadie le gusta
		  que un programa se caiga.
	    </para>
	  </listitem>
	</varlistentry>
      </variablelist>
    </para>

    <para>
	  En resumen, los programadores a menudo contribuyen en
	  su tiempo libre a proyectos de software libre, y aún quienes
	  contribuyen de forma regular pueden detenerse en cualquier
	  instante del tiempo, así que es muy importante que el código
	  sea bueno y les permita modificarlo facilmente.  El resultado
	  final será un mejor software al que los programadores 
	  querrán extender.
    </para>
  </sect1>

  <!-- Coding Style -->

  <sect1 id="code-style">
    <title>Estilo de programación</title>

    <para>
      &lsquo;El estilo de programación&rsquo; se refiere a la forma en 
	  que se da formato al código fuente.  Para C, esto involucra
	  la forma en que se ubican las llaves, se indenta el código y
	  se utilizan los paréntesis.  GNOME tiene una mezcla de estilos
	  de programación y no se obliga el uso de ninguno de ellos.  Lo más
	  importante es que el código sea consistente dentro de un programa
	  o una biblioteca &mdash; el código con un formato desordenado
	  no es aceptable debido a que es difícil de leer.
    </para>

    <para>
	  Cuando escribas un nuevo programa o biblioteca, sigue un
	  estilo consistente de ubicación de llaves y de indentación.
	  Si no tienes ninguna preferencia personal de estilo, 
	  recomendamos el estilo de programación del núcleo de Linux o
	  el estilo de programación de GNU.
    </para>

    <para>
	  Lee el nodo de info <filename>(Standards)Writing C</filename> 
	  en la documentación de GNU. Luego, obtén el código fuente
	  de Linux y lee el archivo 
	  <filename>linux/Documentation/CodingStyle</filename>, e
	  ignora los chistes de Linus.  Estos dos documentos te darán
	  una buena idea de nuestras recomendaciones para el código de
	  GNOME.
    </para>

    <!-- Indentation Style -->

    <sect2 id="indent">
      <title>Estilo de indentación</title>

      <para>
		Para el código del núcleo de GNOME preferimos el estilo
		de indentación del núcleo de Linux.  Usa tabuladores
		de 8 espacios para la indentación.
      </para>

      <para>
		Usar tabuladores de 8 espacios para indentación proporciona
		un número de beneficios.  Permite que el código sea más
		fácil de leer, ya que la indentación se marca claramente.
		También ayuda a mantener el código ordenado
		forzando a dividir funciones en trozos más modulares y
		bien definidos &mdash; si la indentación va más allá del
		margen derecho, significa que la función está mal
		diseñada y que debiera dividirse para hacerla más modular
		o bien, repensarla.
      </para>

      <para>
		Los tabuladores de 8 espacios para indentación también
		ayudan al diseño de funciones que encajen bien en la pantalla, 
		lo cual significa que las personas puedan entender el código
		sin tener que desplazarse atrás y adelante para entenderlo.
      </para>

      <para>
		Si usas &Emacs;, entonces puedes seleccionar el estilo de
		indentación del núcleo de Linux incluyendo en el 
		archivo <filename>.emacs</filename> lo siguiente:

	<programlisting>
(add-hook 'c-mode-common-hook
          (lambda ()
            (c-set-style "k&amp;r")
            (setq c-basic-offset 8)))</programlisting>

	En los nuevos Emacs o con el nuevo cc-mode, puedes ser capaz
	de hacerlo más simple con:

	<programlisting>
(add-hook 'c-mode-common-hook
          (lambda ()
            (c-set-style "linux")))</programlisting>
      </para>

      <para>
		El estilo de indentación de GNU es el predeterminado para
		&Emacs;, así que no es necesario agregar nada en el 
		archivo <filename>.emacs</filename> para habilitarlo.
		Si deseas seleccionarlo explícitamente, sustituye
		«gnu» por «linux» en el ejemplo anterior.
      </para>

      <para>
		Si usas &Vim;, entonces puedes seleccionar el estilo
		de indentación del núcleo de Linux incluyendo el 
		siguiente fragmento en el archivo 
		<filename>.vimrc</filename>:

	<programlisting>
set ts=8
if !exists("autocommands_loaded")
  let autocommands_loaded = 1
  augroup C
      autocmd BufRead *.c set cindent
  augroup END
endif</programlisting>
      </para>

      <para>
		Como alternativa puedes seleccionar el estilo de 
		indentación de GNU en &Vim; usando lo siguiente en
		el archivo <filename>.vimrc</filename>:
	<footnote>
	  <para>
	    Gracias a Tomas &Ouml;gren por proporcionar este código.
	  </para>
	</footnote>:

	<programlisting>
augroup C
   autocmd BufRead *.c set cinoptions={.5s,:.5s,+.5s,t0,g0,^-2,e-2,n-2,p2s,(0,=.5s formatoptions=croql cindent shiftwidth=4 tabstop=8
augroup END</programlisting>
      </para>

      <note>
	<para>
	  Si sabe personalizar el estilo de indentación en otros
	  editores populares, por favor háganoslo saber y así podemos
	  expandir este documento.
	</para>
      </note>
    </sect2>

    <!-- Naming Conventions -->

    <sect2 id="naming">
      <title>Convenciones de nombres</title>

      <para>
		Es importante seguir una buena convención de nombres para
		los símbolos de los programas.   Es específicamente 
		importante para las bibliotecas, ya que no debería
		ensuciarse el espacio de nombres global &mdash; es muy
		molesto cuando una biblioteca tiene símbolos nombrados
		desordenadamente que chocan con nombres que pueda
		querer usar en sus programas.
      </para>

      <para>
		Los nombres de las funciones deberían ser de la forma
		<function>modulo_submodulo_operacion</function>, por ejemplo,
		<function>gnome_canvas_set_scroll_region</function> o
		<function>gnome_mime_get_keys</function>.  Esta convención
		elimina las colisiones de nombres de símbolos entre módulos.
		Es muy importante para las bibliotecas.
      </para>

      <para>
		Los símbolos deben tener nombres descriptivos.  Como Linus
		dice, no use <function>cntusr()</function>, sino que use
		<function>count_active_users()</function>.  Esto permite
		que el código sea más fácil de leer y casi se auto
		documenta.
      </para>

      <para>
		Intente usar las mismas convenciones de nombre que tienen
		GTK+ y las bibliotecas de GNOME:

	<itemizedlist>
	  <listitem>
	    <para>
		  Los nombres de las funciones en minúsculas, con líneas
		  de subrayado para separar palabras, tal como:
	      <function>gnome_canvas_set_scroll_region()</function>,
	      <function>gnome_mime_get_keys()</function>.
	    </para>
	  </listitem>

	  <listitem>
	    <para>
		  Las macros y las enumeraciones en mayúsculas, con líneas
		  de subrayado para separar palabras, tal como:
	      <symbol>GNOMEUIINFO_SUBTREE()</symbol> para una macro y
	      <symbol>GNOME_INTERACT_NONE</symbol> para un valor 
		  enumerado.
	    </para>
	  </listitem>

	  <listitem>
	    <para>
		  Los nombres de tipos y estructuras usan una mezcla de
		  mayúsculas y minúsculas, tal como:
	      <symbol>GnomeCanvasItem</symbol>,
		  <symbol>GnomeIconList</symbol>.
	    </para>
	  </listitem>
	</itemizedlist>

	Al utilizar líneas de subrayado para separar palabras el
	código estará menos apretado y facilita la edición, ya
	que puede usar las secuencias de teclas que permiten
	navegar entre palabras más rápidamente en cualquier editor.
      </para>

      <para>
		Si estás escribiendo una biblioteca, entonces puedes necesitar
		exportar símbolos que serán usados sólo dentro de la
		biblioteca.   Por ejemplo, dos de los archivos objeto que
		componen la biblioteca <filename>libfoo.so</filename> pueden
		requerir acceder a símbolos ubicados en el otro archivo,
		pero se tiene la intención que éstos símbolos no sean 
		utilizados desde los programas de usuario.  En este caso,
		coloca una línea de subrayado antes del nombre de la
		función y haz que la primera palabra siga la convención
		estándar módulo/submódulo.  Por ejemplo, podrías tener
		una función llamada
	<function>_foo_internal_frobnicate()</function>.
      </para>

      <!-- Consistency in Naming -->

      <sect3 id="consist">
	<title>Consistencia entre nombres</title>

	<para>
	  Es importante que las variables se nombren de manera 
	  consistente.  Por ejemplo, un módulo que manipula una
	  lista puedes elegir nombrar las variables que mantienen
	  un puntero a la lista como «<symbol>l</symbol>», 
	  por elegancia y simplicidad.  Sin embargo, es importante que
	  un módulo que manipula widgets y tamaños no use variables
	  llamadas «<symbol>w</symbol>» tanto para
	  widgets y anchos («width») (como en valores de ancho/alto);
	  esto podría hacer que el código sea inconsistente
	  y difícil de leer.
	</para>

	<para>
	  Por supuesto, nombre muy cortos y elegantes solamente deberían
	  ser usados para variables locales de funciones.
	  Nunca llame una variable global «<symbol>x</symbol>»; use 
	  un nombre más largo que indique lo que significa.
	</para>
      </sect3>
    </sect2>

    <!-- Cleanliness -->

    <sect2 id="clean">
      <title>Limpieza</title>

      <para>
		El código de GNOME debe ser tan limpio como sea posible.
		Esto implica usar un estilo de indentación consistente
		y una buena convención para nombrar símbolos, como se
		ha indicado anteriormente.  Esto también implica lo
		siguiente.
      </para>

      <para>
		Aprender el uso correcto de la palabra reservada
		<symbol>static</symbol>.
		<emphasis>No</emphasis> declarar todos los símbolos como
		globales.  Esto tiene la ventaja de poder usar nombres
		más cortos dentro de las funciones en un sólo archivo
		fuente, ya que no son globalmente visibles y por
		consiguiente no necesitas emplear el prefijo 
		módulo/submódulo.
      </para>

      <para>
		Aprender el uso correcto de la palabra reservada
		<symbol>const</symbol>.  Úsala consistentemente,
		así permitirás al compilador que atrape muchos
		errores estúpidos.
      </para>

      <para>
		Si tienes una función que retorna un puntero a
		un dato interno que se supone que el usuario
		no debe liberar, deberías usar el modificador
		<symbol>const</symbol>.  Este avisará al usuario si intenta 
		hacer alguna operación incorrecta, por ejemplo:

	<programlisting>
const char *gnome_mime_get_info (const char *info);</programlisting>

		El compilador avisará si el usuario intenta liberar
		la cadena retornada.  Esto puede atrapar muchos
		errores.
      </para>

      <para>
		Si tienes «valores mágicos» en el programa o
		biblioteca, usa macros que los definan en vez de usarlos
		directamente en el código:

	<programlisting>
/* Amount of padding for GUI elements */
#define GNOME_PAD          8
#define GNOME_PAD_SMALL    4
#define GNOME_PAD_BIG      12</programlisting>
      </para>

      <para>
		Si tienes una lista de valores posibles para una variable,
		no uses macros para ellas, usa enum para darle 
		un nombre de tipo &mdash; esto permite disponer de nombres
		simbólicos en un depurador.  Además, no uses 
		«int» para almacenar un valor enumerado; usa
		el tipo enum.  Esto le permite al compilador atrapar
		los errores por tí, permitiéndole al depurador mostrar los
		valores apropiados y hacer obvios los valores que una 
		variable puede tomar. A continuación un ejemplo:

	<programlisting>
/* Shadow types */
typedef enum {
	GTK_SHADOW_NONE,
	GTK_SHADOW_IN,
	GTK_SHADOW_OUT,
	GTK_SHADOW_ETCHED_IN,
	GTK_SHADOW_ETCHED_OUT
} GtkShadowType;

void gtk_frame_set_shadow_type (GtkFrame *frame, GtkShadowType type);</programlisting>
      </para>

      <para>
	Si define un conjunto de valores para un campo de bits, haz
	lo siguiente:

	<programlisting>
<![CDATA[
/* Update flags for items */
enum {
	GNOME_CANVAS_UPDATE_REQUESTED  = 1 << 0,
	GNOME_CANVAS_UPDATE_AFFINE     = 1 << 1,
	GNOME_CANVAS_UPDATE_CLIP       = 1 << 2,
	GNOME_CANVAS_UPDATE_VISIBILITY = 1 << 3,
	GNOME_CANVAS_UPDATE_IS_VISIBLE = 1 << 4
};]]></programlisting>

	Esto hace más fácil modificar la lista de valores y menos 
	propenso a error que especificando los valores a mano.  También
	permite usar estos valores como símbolos en un depurador.
      </para>

      <para>
		No escribas código ofuscado, intenta que sea espartano. 
		Para clarificar una expresión, no uses más paréntesis que 
		los necesarios.  Usa espacios antes de los paréntesis y
		después de las comas y también alrededor de los operadores
		binarios.
      </para>

      <para>
		No escribas hacks en el código.  En vez de escribir un 
		hack feo, reescribe el código para que quede limpio,
		extensible y mantenible.
      </para>

      <para>
		Asegúrate de que el código compila absolutamente sin ningún
		aviso del compilador.  Esto te ayudará a atrapar errores
		estúpidos.  Usa los prototipos de las funciones en los
		archivos de encabezados de forma consistente.
      </para>

      <para>
		Dentro de GNOME puedes usar la macro de Autoconf 
        <symbol>GNOME_COMPILE_WARNINGS</symbol> en el archivo
        <filename>configure.in</filename>.  Esto permitirá contar
		con un buen conjunto de avisos del compilador de una manera
		portable.
      </para>

      <para>
		Comenta el código.  Coloca comentarios antes de
		cada función para decir que hace.  No digas cómo lo hace
		a menos que sea absolutamente necesario; debería ser 
		obvio al leer el código.  Si no lo fuera, entonces
		puedes desear reescribirla hasta que sea fácil de 
		entender.
      </para>

      <para>
		Cuando documentes las funciones de la API de una biblioteca,
		sigue las directrices indicadas en el archivo
        <filename>gnome-libs/devel-docs/api-comment-style.txt</filename>.
		Esto permite que el código fuente pueda proporcionar documentación
		en línea, que posteriormente se extrae mediante el sistema
        <application>gtk-doc</application> para crear un manual DocBook
	  	de forma automática.
      </para>

      <!-- Portability considerations -->

      <sect3 id="portability">
	<title>Consideraciones de portabilidad</title>

	<para>
	  Se construye GNOME en muchas plataformas diferentes.
	  Se puede asumir que serán plataformas más o menos tipo Unix;
	  hasta el momento GNOME no ha sido portado a sistema no-Unix,
	  así que se puede asumir que los servicios estándares de 
	  Unix estarán disponibles.<footnote>
	    <para>
		  ¿Servicios estándar de Unix? Por supuesto que estamos
		  bromeando.
	    </para>
	  </footnote>
	</para>

	<para>
	  Recuerda que el mundo no es tu propio equipo con GNU/Linux;
	  las gente realmente usa otros tipos de máquinas.
	</para>

	<para>
	  Intenta no usar extensiones específicas de
	  <application>GCC</application> debido a que éstas no 
	  funcionarán con otros compiladores.  Si realmente debes
	  hacer uso de tal cosa, ve la forma en que se hace
	  en <application>Glib</application> con el conjunto de
	  macros G_GNUC; asegúrate también de incluir código
	  que funcione con compiladores ISO C. Si sólo tienes
	  disponible <application>GCC</application>, aprende a usar
	  las opciones <option>-ansi -pedantic</option> que
	  permiten probar código sospechoso.
	</para>

	<para>
	  Recuerda que algunas plataformas no disponen de
	  <application>GCC</application> o que
	  <application>GDB</application> puede ser inusable en ellos,
	  y se querrán usar otros compiladores y depuradores.
	</para>
      </sect3>

      <!-- GTK+-related Issues -->

      <sect3 id="gtk">
	<title>Tópicos relacionados con GTK+</title>

	<para>
	  GTK+ permite hacer mucha magia y ofuscación con manejadores
	  de señal, pasar cerraduras y conjuntos de datos.  Si te
	  encuentras utilizando muchos 
	  <function>gtk_object_set_data()</function> en un mismo lugar,
	  o estas pasando estados de forma extraña a través de manejadores
	  de señales, reescribe el código.  Si necesitas adjuntar muchos
	  datos a un objeto en particular, entonces es un buen candidato
	  para una nueva clase derivada, que no sólo hará al código
	  más limpio, sino que también lo hará más extensible.
	</para>

	<para>
      Mucha de la heurística en manejadores de eventos complicadas
	  a menudo se pueden reemplazar limpiando el código a través
	  de una máquina de estados.  Esto es útil cuando se quieren
	  implementar cosas truculentas como selección y comportamientos
	  de arrastrado, y hará al código más fácil de depurar y extender.
	</para>
      </sect3>
    </sect2>
  </sect1>

  <!-- Correctness and Robustness -->

  <sect1 id="robust">
    <title>Corrección y robustez</title>

    <para>
	  Es extremadamente importante que el código de GNOME sea
	  correcto y robusto.  Esto significa que el código debería hacer
	  lo que se espera que haga y debería manejar bien las condiciones
	  de excepción.  Aunque esto pueda parecer obvio, esta sección
	  dará algunas ideas para asegurar la corrección de tu código
	  de GNOME.  Esto es muy importante, ya que los usuarios esperan
	  y merecen un software confiable que se ejecute correctamente
	  y que no se caiga.
    </para>

    <!-- Ensuring Consistency -->

    <sect2 id="ensure">
      <title>Cómo asegurar la consistencia</title>

      <para>
	  	<!-- FIXME: Buscar un mejor termino para "assertion" -->
		Utiliza las macros de aserción de Glib para asegurarte
		que el estado de un programa es consistente.  Estas macros
		ayudan a localizar errores muy rápidamente y se gastará 
		mucho menos tiempo en el depurado si se emplean de forma
		generosa y consistente.
      </para>

      <para>
		Inserta verificaciones de sanidad en el código en puntos
		importantes como es el inicio de funciones públicas, al
		final de código que realiza una búsqueda que siempre
		debe ser exitosa y en cualquier lugar donde
		el rango de valores calculados es importante.
      </para>
    </sect2>

    <!-- Assertions and Preconditions -->

    <sect2 id="assert">
      <title>Aserciones y precondiciones</title>

      <para>
		Las aserciones y precondiciones ayudan a asegurar que
		el estado de un programa es consistente.  Glib proporciona
		macros para colocar aserciones y precondiciones en el
		código.  Deberías usarlas libremente; a cambio podrás
		localizar errores muy rápidamente y ocuparás menos tiempo
		rastreando errores con el depurador.
      </para>

      <para>
		Existen macros de Glib para precondiciones, las cuales
		emiten un mensaje cuando una condición falla y retornan
		de la función desde donde fueron llamadas.  Debieran ser
		usadas en el inicio de las funciones.

	<variablelist>
	  <varlistentry>
	    <term><function>g_return_if_fail
		(condición)</function></term>
	    <listitem>
	      <para>
			Retorna desde la línea actual de la función si la
		<symbol>condición</symbol> es falsa.
	      </para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><function>g_return_val_if_fail (condición,
		valor)</function></term>
	    <listitem>
	      <para>
			Retorna el <symbol>valor</symbol> indicado desde
			la función actual si la <symbol>condición</symbol>
			es falsa.
	      </para>
	    </listitem>
	  </varlistentry>
	</variablelist>
      </para>

      <para>
		También existen macros para aserciones.  Estas emitirán
		un mensaje cuando una condición falle y llamará a la
		función <function>abort(3)</function> para terminar el
		programa.  Debieran ser usadas para asegurarse la
		consistencia para códigos internos.

	<variablelist>
	  <varlistentry>
	    <term><function>g_assert (condición)</function></term>
	    <listitem>
	      <para>
			Aborta el programa si la <symbol>condición</symbol>
			es falsa.
	      </para>
	    </listitem>
	  </varlistentry>

	  <varlistentry>
	    <term><function>g_assert_not_reached ()</function></term>
	    <listitem>
	      <para>
			Aborta el programa si se llama a la macro.
	      </para>
	    </listitem>
	  </varlistentry>
	</variablelist>
      </para>

      <para>
		Estas funciones debieran emplearse para imponer 
		precondiciones en el código y verificar su corrección
		&mdash; piensa en ellas como verificaciones de sanidad
		en los programas.  Debieras usarlas libremente como
		asistencia para atrapar los errores rápidamente; una
		vez que el programa se encuentre completamente depurado,
		puedes compilarlo con estas macros deshabilitadas y así
		evitar añadirle sobrecarga al momento de ejecutarlos.
      </para>

      <para>
		Las macros <function>g_return_*()</function> debieran 
		emplearse al inicio de las funciones públicas de las
		bibliotecas, para asegurarse de que los argumentos que se pasan
		a ellas sean correctos y tengan un rango válido.  Si
		una función no retorna valor (por ejemplo, retorna
		<symbol>void</symbol>), debieras usar 
		<function>g_return_if_fail()</function>.  En caso contrario,
		debiera usar <function>g_return_val_if_fail()</function> 
		para retornar un valor &lsquo;seguro&rsquo;.  Cuando
		se invoca una función de biblioteca que usa estas macros 
		con un argumento incorrecto , se producirá un
		mensaje de error y continuará la ejecución.  El
		programa cliente podrá tener algún sobresalto, hacer
		nada o caerse, pero al menos sabrá 
		<emphasis>dónde</emphasis> se le ha pasado un valor 
		incorrecto a la función.
      </para>

      <para>
	  	La macro <function>g_assert()</function> debiera usarse para
		asegurar la consistencia interna de una biblioteca o
		programa.  En vez de retornar de la función y continuar
		la ejecución si la condición falla, 
		<function>g_assert()</function> producirá en mensaje de error
		e inmediatamente abortará el programa.  Esto es para
		evitar que el programa continúe ejecutándose en un
		estado inconsistente.  Debieras usar esta macro para
		asegurarte de que el programa o biblioteca está usando
		valores internos sanos.
      </para>

      <para>
		La macro <function>g_assert_not_reached()</function> se
		usa para marcar el lugar en el código que nunca 
		debiera producirse.  Por ejemplo, si tienes una 
		cláusula <symbol>switch</symbol> y piensas que manejas
		todos los valores posibles en las etiquetas
		<symbol>case</symbol>, entonces debieras colocar 
		<function>g_assert_not_reached()</function> en la 
		etiqueta <symbol>default</symbol> para asegurarte de que
		el código nunca llegue allá (podría significar que
		ha perdido algún valor o que el programa se encuentra
		incorrecto).
      </para>

      <para>
		Estas macros ayudan a encontrar errores más rápido 
		a través de avisos que se producen tan pronto como
		el programa alcanza un estado incosistente.  Úsalos
		frecuentemente y encontrarás muchos errores más 
		fácilmente.
      </para>
    </sect2>

    <!-- GTK+-related Issues -->

    <sect2 id="assert-gtk">
      <title>Tópicos relacionados con GTK+</title>

      <para>
		Debe ser cuidadoso cuando escribas manejadores de eventos 
		&mdash; asegurate de que los eventos son manipulados en
		las situaciones apropiadas.  Es necesario asegurarse de
		que los manejadores de señales tengan los prototipos
		correctos.  Esto es muy importante.  Recuerda que no
		todos los prototipos de manejadores de señal se parecen
		a lo siguiente:

	<programlisting>
static void my_handler (GtkWidget *widget, gpointer data);</programlisting>

	Por ejemplo, los manejadores de eventos tienen un parámetro
	extra de evento y retornan <symbol>gint</symbol>.  Revisa los
	archivos de encabezado de GTK+ cuando necesites verificarlo.
      </para>

      <para>
		Asegúrate que el programa trata de una forma apropiada
		todas las acciones generadas por el usuario.  Recuerda
		que el usuario puede cerrar una ventana en cualquier 
		momento a través del administrador de ventanas; tenlo
		presente y escribe el código necesario para manejar esta
		situación.
      </para>

      <para>
		Si verificas los modificadores de teclas con una máscara
		de estado de eventos, por ejemplo,
		<keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
		escribe lo siguiente:

	<programlisting>
  guint modifiers;

  modifiers = gtk_accelerator_get_default_mod_mask ();

  if (event-&gt;keysym == GDK_F10
      &amp;&amp; (event-&gt;state &amp; modifiers) == GDK_CONTROL_MASK) {
          do_something ();
  }</programlisting>

	Esto es necesario; si en vez de lo anterior escribes:

	<programlisting>
  if (event-&gt;keysym == GDK_F10 &amp;&amp; event-&gt;state == GDK_CONTROL_MASK)</programlisting>

		entonces el programa no funcionará correctamente si el
		usuario tiene, por ejemplo, activada la tecla 
		<keycap>NumLock</keycap> &mdash; <keycap>NumLock</keycap> 
		también es un modificador, y si está activado, entonces
		la máscara de estado del evento no será como se espera
		en el segundo ejemplo.
      </para>

      <!-- Visuals and Colormaps -->

      <sect3 id="visuals">
	<title>Vistas y mapas de color</title>

	<para>
	  <!-- FIXME: Buscar un término adecuado para "Visual" en
	       vez de "vista" -->
	  Algunos usuarios utilizan tarjetas de vídeo avanzadas
	  (por ejemplo, SGIs y Suns) que soportan múltiples vistas
	  simúltaneamente.  Una vista define la representación en memoria
	  que usa un dispositivo de hardware para almacenar los 
	  contenidos de una imagen.  Muchas tarjetas de vídeo de
	  PC soportan sólo una vista a la vez, pero el hardware
	  avanzado puede tener diferentes ventanas y pixmaps en
	  diferentes vistas simultáneamente.
	</para>

	<para>
	  Es importante entender las vistas y mapas de colores si
	  vas a escribir código que crea ventanas y pixmaps por tus
	  propios medios, en vez de utilizar las funciones de alto
	  nivel como GnomeCanvas y GnomePixmap.  Para mayor información,
	  lea el manual de programación de Xlib.
	</para>

	<para>
	  En general, sólo necesitas recordar que la vista y el mapa
	  de colores de un área de dibujo debe coincidir con los de 
	  otra área de dibujo si deseas copiar un trozo desde la
	  primera área de dibujo a la segunda.  Si no son las mismas,
	  podrías obtener el mensaje «BadMatch error» del servidor X y
	  tu aplicación muy probablemente abortará su ejecución.
	</para>

	<para>
	  Si creas un contexto gráfico (GC) y lo compartes para pintar
	  en varias áreas de dibujo, asegúrate que todas ellas tengan
	  la misma vista y mapa de colores que fue definido para el 
	  GC.  Lo mismo se aplica si quieres copiar un área desde un
	  pixmap a una ventana; ambos deben tener la misma vista y mapa
	  de colores.
	</para>

	<para>
	  Si no estás seguro de que tu código lo hace correctamente, 
	  pregunta educadamente, en una de las listas de correo de 
	  desarrollo de GNOME, si alguien puede realizar una prueba con
	  una tarjeta de video que soporta esta característica.  Dicha 
	  persona sabrá como arreglar el problema y te dirá al respecto.
	</para>
      </sect3>
    </sect2>

    <!-- Unix-related Issues -->

    <sect2 id="unix">
      <title>Temas relacionados con Unix</title>

      <para>
		Verifica los valores de retorno de <emphasis>todas</emphasis>
		las llamadas al sistema que el programa realice.  Recuerda
		que muchas de las llamadas al sistema pueden ser 
		interrumpidas (por ejemplo, la llamada retorna 
	    <symbol>-1</symbol> y <symbol>errno</symbol> será definido a 
	    <symbol>EINTR</symbol>) y deben reiniciarse.
      </para>

      <para>
		No asumas, por ejemplo, que la función 
		<function>write(2)</function> escribirá el buffer completo
		de una vez; tienes que verificar el valor de retorno, el cual
		indica el número de bytes escritos e intenta nuevamente 
		hasta que sea cero.  Si el valor de retorno es 
	    <symbol>-1</symbol>, recuerda
		verificar el valor de errno y manejar el error 
		apropiadamente.
      </para>

      <para>
		Si la aplicación llama a la función <function>fork(2)</function>
		sin llamar a <function>execve(2)</function>, recuerda que
		el proceso hijo no puede hacer llamadas X.  Normalmente se
		puede diagnosticar este problema a través de un oscuro
		mensaje de error de Xlib.
      </para>

      <para>
		Lee el libro «Advanced programming in the Unix 
		environment», de Richard Stevens, para aprender acerca de
		todos estos teassertmas y asegúrate que tus programas usan
		la API de Unix de forma correcta.  Si no deseas asegurarte
		del uso correcto de las llamadas Unix, pregunta en las
		listas de correo.
      </para>
    </sect2>
  </sect1>

  <!-- Security Considerations -->

  <sect1 id="security">
    <title>Consideraciones de seguridad</title>

    <para>
	  La seguridad es un tema complejo y en esta sección no se
	  puede explicar ni de lejos todo lo relacionado.
	  Intentaremos indicar las situaciones más comunes donde tus
	  programas deben interesarse por la seguridad.
    </para>

    <para>
	  Es muy fácil crear hoyos de seguridad a través de la creación
	  incorrecta de archivos temporales en <filename>/tmp</filename>.
	  Debes garantizar que los archivos que usarás no existen al 
	  momento de su creación.  Usar un nombre de archivo «único»
	  e «impredecible» no es suficiente; debes garantizar que el archivo
	  con ese nombre no será creado por alguien más entre el tiempo
	  en que se determina el nombre y el tiempo en que es efectivamente
	  creado (básicamente los ataques involucran que un tercero
	  cree un enlace simbólico al archivo que ellos quieren 
	  sobreescribir).
    </para>

    <para>
	  Afortunadamente, esto es fácil de hacer.  Usa el siguiente trozo
	  de código:

      <programlisting>
	char *filename;
	int fd;

	do {
		filename = tempnam (NULL, "foo");
		if (!filename) {
			fprintf (stderr, "Could not create temporary file name\n");
			exit (EXIT_FAILURE);
		}

		fd = open (filename, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
		free (filename);
	} while (fd == -1);</programlisting>

      Recuerde liberar <symbol>filename</symbol> usando la función
	  <function>free()</function> y llamar a las funciones 
	  <function>close()</function> y <function>unlink()</function> 
	  con el archivo respectivo cuando haya terminado; aquí
	  liberamos <symbol>filename</symbol> con <function>free()</function>
	  inmediatamente y así no causará una pérdida de memoria.
    </para>

    <para>
	  Si deseas usar la biblioteca estándar de E/S, puede usar la
	  función <function>fdopen()</function> para transformar el
	  descriptor de archivo en <symbol>FILE *</symbol>, o puedes
	  usar la función <function>tmpfile()</function> para hacerlo 
	  en un solo paso.
    </para>

    <para>
	  Intenta no usar buffers de tamaño fijo.  Los buffers de tamaño
	  fijo para cadenas constituyen los típicas fuentes de hoyos
	  explotables que pueden llegar a oscuros errores.  Si definitivamente
	  debes usar buffers de tamaño fijo para cadenas, usa la función
      <function>g_snprintf()</function> para especificar el tamaño 
	  máximo del buffer.
    </para>

    <para>
	  Glib proporciona la, muy conveniente, función 
      <function>g_strdup_printf()</function>, la cual funciona como
      <function>sprintf()</function> pero automáticamente 
	  localizará un buffer con el tamaño correcto.  El valor de retorno
	  de esta función debiera ser liberada usando
	  <function>g_free()</function>.  A menudo es más conveniente de
	  usar que <function>g_snprintf()</function>, ya que esta no 
	  limita el tamaño de las cadenas que un programa puede manipular.
    </para>

    <para>
	  Si deseas concatenar un grupo de cadenas, puedes usar la función
      <function>g_strconcat()</function>, la cual recibe una lista
	  variable de cadenas y un puntero a <symbol>NULL</symbol>
	  como último argumento.
    </para>

    <para>
      <emphasis>Bajo ninguna circunstancia</emphasis> crees un 
	  programa GTK+ con setuid root.  Las bibliotecas de GTK+ y
	  GNOME son grandes y complejas y no han tenido auditorías
	  de seguridad.  En cualquier caso, no debieras querer que 
	  una pieza tan grande código sea setuid root.  Si definitivamente
	  requieres usar privilegios de root para algo, escribe un 
	  programa que sea la interfaz de usuario como un proceso
	  normal, sin privilegios y crea un programa nexo que
	  tenga setuid y se encargue de realizar la operaciones
	  «peligrosas».  Además, notifica a las listas
	  de correo de desarrollo de GNOME indicando que requieres
	  que alguien realice una auditoría de seguridad a tu
	  programa nexo.
    </para>

    <para>
	  En general, si no estás seguro si puedes crear un riesgo de
	  seguridad, pregunte en las listas de correo de desarrollo
	  de GNOME.
    </para>

    <para>
	  Puedes leer más sobre temas de seguridad que debieras encontrar
	  cuando programes una aplicación Unix en el documento
      <ulink URL="http://www.fish.com/security/murphy.html">«Murphy's
      Law and Computer Security»</ulink>, de Wietse Wenema.  
	  Hay otros documentos de seguridad en <ulink
      URL="http://www.fish.com/security">el sitio fish.com</ulink>
	  que podrías encontrar interesante.
    </para>

    <para>
	  Puedes encontrar muchas otras guías útiles para escribir programas
	  seguros en <ulink
      url="http://www.dwheeler.com/secure-programs">«Secure
      Programming for Linux and Unix HOWTO»</ulink>.
    </para>
  </sect1>

  <!-- Performace -->

  <sect1 id="performance">
    <title>Rendimiento</title>

    <para>
	  No leas esta sección hasta que estés seguro que tu programa está
	  correcto, por ejemplo, cuando estés seguro que funciona 
	  correctamente y no tiene errores.  Es más importante que
	  el código sea correcto a que sea rápido.  Un programa lento
	  pero correcto es mucho mejor a uno rápido pero con errores.
    </para>

    <para>
	  Si quieres optimizar tu programa, el primer paso es determinar
	  un perfil al programa ejecutándolo con datos de la vida real
	  y recopilar puntos calientes que requieran optimización.
	  Esto ayudará a determinar los lugares que necesitan optimizarse.
	  Es importante que nunca adelantes la optimización si no tienes
	  una idea clara sobre donde está el problema.  Podrías terminar 
	  perdiendo el tiempo en agilizar una rutina que no es la causa 
	  del cuello de boteLla y como resultado podrías terminar ofuscando 
	  dicha rutina.  Esto podría reducir la legibilidad y mantenibilidad
	  del código sin ganancia visible en velocidad.
    </para>

    <para>
	  Un código sencillo es bueno porque es fácil de entender y 
	  mantener.  Si puedes escribir código simple que además sea
	  potente y rápido, tanto mejor.  Si tienes un trozo de código
	  inteligente pero que no es fácil de seguir, entonces documéntalo
	  para que las personas no lo estropeen accidentalmente.
    </para>

    <para>
	  No escribas código que sea difícil de leer y mantener por el
	  sólo hecho de hacerlo más rápido.  En cambio, prefiere un algoritmo
	  agradable y claro e impleméntalo claramente.
    </para>

    <para>
	  Hacer un buen trabajo en el caso general es a menudo mejor que
	  tener muchos casos especiales.  Sólo provee casos especiales
	  cuando se han identificado puntos débiles en el programa.
    </para>

    <!-- List Management in Glib -->

    <sect2 id="list">
      <title>Administración de listas en Glib</title>
    	<para>
		  Evita emplear construcciones que terminen ralentizando
		  los algoritmos.  Si usas
		  <function>g_list_insert_sorted()</function> o
    	  <function>g_list_append()</function> sin ningún cuidado,
		  fácilmente puedes tener un algoritmo que se ejecuta en
		  tiempo proporcional a O(n<superscript>2</superscript>).  
		  Normalmente puedes crear listas hacia atrás, usando
    	  <function>g_list_prepend()</function>, e invirtiéndola
		  cuando hayas terminado usando 
		  <function>g_list_reverse()</function>.  Esta es una
		  operación O(n).  Y si necesitas una lista ordenada, puedes
		  crearla de la misma forma (hacia atrás) y una vez terminado,
		  usar <function>g_list_sort()</function>.
    	</para>

    	<para>
		  Si necesitas una lista ordenada en todo momento, puede ser
		  mejor emplear un estructura de árbol o un híbrido 
		  lista/árbol.  Si necesitas construir una lista añadiendo
		  nodos a ella, mantén un puntero al final de la lista
		  y ve cambiándola según sea apropiado; esto te permitirá
		  insertar un nodo al inicio o al final en un tiempo constante.
    	</para>
    </sect2>
  </sect1>

  <!-- Localization -->

  <sect1 id="l10n">
    <title>Localización</title>

    <para>
	  Se pretende que GNOME pueda ejecutarse en distintas localidades
	  y lenguajes, y los programas debieran tener esto en cuenta.  No
	  tienes que localizar los programas, sólo debes permitir que éstos
	  sean traducibles y localizables.
    </para>

    <para>
	  Debes recordar que los diferentes idiomas humanos tienen diferentes
	  gramáticas, así que no debieras suponer la forma de estructurar
	  cada frase.  Esto es importante, por ejemplo, cuando se 
	  construyen cadenas a partir de trozos separados.
    </para>

    <para>
	  La concatenación normalmente no es la forma correcta de construir
	  una cadena para que sea presentada al usuario.  Normalmente terminan
	  en mensajes que no pueden ser traducidos correctamente en todos
	  los idiomas.  En vez de concatenar, intenta usar
	  <function>g_strdup_printf()</function>, por ejemplo:

      <programlisting>
	/* Una forma no muy buena */
	char *message = g_strconcat (_("Hello, "),
				     name,
				     _(", would you like fries with that?"),
				     NULL);

	/* Una mejor forma */
	char *message = g_strdup_printf (_("Hello, %s, would you like fries with that?"),
					 name);</programlisting>

	  Esto permitirá al traductor mover %s donde corresponda según
	  lo requiera la gramática del idioma en el cual trabaja.
    </para>

    <para>
	  Recuerda que no todos los idiomas forman los plurales añadiendo
	  una «s» a las palabras.  Además, las estructuras de
	  frases pueden cambiar con los plurales.  Por ejemplo,

      <programlisting>
	/* Una forma no muy buena */
	printf (_("%d happy monkey%s bouncing on the bed."),
		num_monkeys,
		(num_monkeys > 1) ? "s", "");

	/* Una mejor forma */
	printf ((num_monkeys > 1)
		? _("%d happy monkeys bouncing on the bed."),
		: _("%d happy monkey bouncing on the bed."));</programlisting>

	  Se requiere de esta forma ya que el plural se forma de 
	  distintas maneras en distintos idiomas, y la estructura
	  completa de la frase puede cambiar.
    </para>

    <para>
	  Si el programa muestra fechas u horas, usa la función
      <function>strftime()</function> para darles formato como
	  cadenas.  Esto se encargará de usar la representación
	  adecuada de fecha y hora de acuerdo a la definición local
	  del usuario.  Además, si el programa debe generar una
	  representación visual de un calendario, recuerda que en
	  algunos países se considera como primer día de la semana
	  el domingo y no el lunes.  El programa debiera permitir 
	  ambas formas de calendarios.
    </para>

    <para>
	  Si el programa usa medidas, asegúrate de permitir tanto
	  el sistema métrico decimal como el sistema imperial (o anglosajón).
    </para>
  </sect1>

  <!-- Binary Compatibility -->

  <sect1 id="binary">
    <title>Compatibilidad binaria en las bibliotecas</title>

    <para>
	  Para bibliotecas estables y ya liberadas, es muy importante
	  intentar preservar la compatibilidad binaria en las revisiones
	  mayores del código.  Los desarrolladores de bibliotecas deben
	  intentar no alienar a los usuarios realizando de forma frecuente
	  cambios que sean binariamente incompatibles en bibliotecas que
	  son de producción.  Por supuesto, en aquellas bibliotecas que se
	  encuentran en desarrollo o están etiquetadas como no finalizadas
	  puedes realizar tantos cambios como se necesiten.
    </para>

    <para>
	  Una biblioteca típicamente exporta un número de interfaces.  Estas
	  incluyen nombres de rutinas, las firmas o prototipos de estas
	  rutinas, variables globales, estructuras, campos de estructura
	  (tanto los tipos como su significado), el significado de los
	  valores enumerados y la semántica de los archivos que la
	  biblioteca crea.  Mantener compatibilidad binaria significa que
	  estas interfaces no cambiarán.  Puedes añadir nuevas interfaces
	  sin romper la compatibilidad binaria, pero no puedes cambiar
	  las ya existentes, ya que los programas antiguos no se ejecutarán
	  correctamente.
    </para>

    <para>
	  Esta sección incluye un número de ideas acerca de como lograr
	  que el código de una biblioteca sea compatible con sus
	  versiones anteriores.
    </para>

    <para>
	  Mantener la compatibilidad binaria significa que los programas
	  y archivos objetos que fueron compilados con una versión 
	  previa del código continuarán funcionando sin recompilar aún
	  cuando la biblioteca sea reemplazada. Es posible encontrar
	  una descripción detallada en el nodo info
      <filename>(libtool)Interfaces</filename> de la documentación
	  de GNU libtool.
    </para>

    <!-- Private Information in Structures -->

    <sect2 id="private">
      <title>Información privada en las estructuras</title>

      <para>
		En el sistema GNOME es una tarea muy común crear un
		nuevo <structname>GtkObject</structname> para crear
		una estructura cuyo primer miembro corresponde a la 
		clase de la cual hereda este objeto y posteriormente
		un número de variables de instancia que se añaden 
		después del primer miembro.
      </para>

      <para>
		Este esquema de diseño normalmente lleva a que el código
		sea difícil de actualizar y cambiar: si se quiere
		extender un objeto donde se necesita mantener su estado 
		interno, los programadores necesitan recurrir a varios 
		hacks para mantener el mismo tamaño de las estructuras.  
		Esto hace difícil agregar nuevos campos a las estructuras 
		públicas sin romper la compatibilidad binaria, ya que 
		los campos de la estructura pueden cambiar y el tamaño 
		de las estructuras pueden variar.
      </para>

      <para>
		Por consiguiente, se sugiere una estrategia que puedan
		adoptar los desarrolladores en el momento de crear nuevos
		objetos.  Esta estrategia asegurará la compatibilidad
		binaria y al mismo tiempo mejorará la legibilidad y 
		mantenibilidad del código.
      </para>

      <para>
		La idea es que, para un objeto dado, el programador
		debiera crear tres archivos: el primero que contiene
		el contrato entre la biblioteca y el usuario (esto
		es el archivo de encabezado que se instala en el 
		sistema); el segundo contiene la implementación del
		objeto; y el tercer archivo contiene la definición 
		de la estructura para los campos privados o internos
		que no necesitan estar en la estructura pública.
      </para>

      <para>
		La API pública de la estructura podría incluir un
		puntero a un elemento privado, el cual podría 
		apuntar a los datos privado de la instancia. Las
		rutinas de implementación podría dereferenciar
		este punto para acceder a los datos privados; por
		supuesto, el puntero apunta a la estructura que se
		localiza privadamente.
      </para>

      <para>
		Por ejemplo, imagina que se crea el objeto GnomeFrob. 
		La implementación del widget será dividido en tres 
		archivos:

	<table>
	  <title>Archivos que muestran el widget de ejemplo 
	  GnomeFrob</title>

	  <tgroup cols="2">
	    <thead>
	      <row>
		<entry>Archivo</entry>
		<entry>Contenido</entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<entry><filename>gnome-frob.h</filename></entry>
		<entry>API pública de GnomeFrob</entry>
	      </row>
	      <row>
		<entry><filename>gnome-frob.c</filename></entry>
		<entry>Implementación del objeto Gnomefrob</entry>
	      </row>
	      <row>
		<entry><filename>gnome-frob-private.h</filename></entry>
		<entry>Datos privados de la implementación de GnomeFrob.
			Debieras querer usar esto si planea compartir los
			datos privados a través de varios archivos C. Si
			limitas el uso de la información privada a sólo un
			archivo, no necesita esto, ya que al definir la
			estructura en el archivo de implementación se logrará
			el mismo efecto.</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</table>
      </para>

      <para>
	<example>
	  <title>Ejemplo de la API pública de <filename>gnome-frob.h</filename>
	  </title>
	  <programlisting>
typedef struct _GnomeFrob GnomeFrob;
typedef struct _GnomeFrobPrivate GnomeFrobPrivate;

struct _GnomeFrob {
       GtkObject parent_object;

       int  public_value;
       GnomeFrobPrivate *priv;
} GnomeFrob;

GnomeFrob *gnome_frob_new (void);
void       gnome_frob_frobate (GnomeFrob *frob);</programlisting>
	</example>

	<example>
	  <title>Ejemplo de 
	  <filename>gnome-frob-private.h</filename></title>
	  <programlisting>
typedef struct {
        gboolean frobbed;
} GnomeFrobPrivate;</programlisting>
	</example>

	<example>
	  <title>Ejemplo de la implementación de 
	  <filename>gnome-frob.c</filename>.</title>
	  <programlisting>
void gnome_frob_frobate (GnomeFrob *frob)
{
        g_return_if_fail (frob != NULL);
	g_return_if_fail (GNOME_IS_FROB (frob));

	frob->priv->frobbed = TRUE;
}</programlisting>
	</example>

		Fíjese en el uso de prototipos de estructura: esto permite que
		el compilador realice más verificaciones en tiempo de
		compilación respecto a los tipos que estan siendo empleados.
      </para>

      <para>
		Este esquema es útil en algunas situaciones, particularmente
		en el caso en el cual vale la pena almacenar un puntero
		extra para una instancia del objeto.  Si esto no fuera
		posible, el programador necesitaría recurrir a otros
		artilugios para evitar este problema.
      </para>

      <para>
		El propósito de tener un archivo de encabezado privado
		extra para las estructuras privadas es permitir que las
		clases derivadas usen esta información.  Por supuesto,
		una buena práctica de programación indicaría que debiera
		proveerse de interfaces o métodos de acceso precisamente
		para que el programador no tenga que lidiar con 
		estructuras privadas.  Se debiera intentar alcanzar un 
		balance entre buena práctica y pragmatismo cuando se
		crean estructuras privadas y métodos de acceso públicos.
      </para>

      <para>
		Podrían aparecer algunos problemas, por ejemplo, cuando
		se ha enviado un versión del código y que está siendo
		ampliamente usado y se desea extenderlo.  Hay dos 
		soluciones para esto.
      </para>

      <para>
		La primera opción es encontrar un campo puntero en la
		estructura pública que pueda hacerse privada y 
		reemplazar el puntero a la parte privada de la 
		estructura.  Esto preserva el tamaño de la estructura
		ya que, para los propósitos de GNOME, se puede
		asumir que los punteros son todos del mismo tamaño.
		Se puede hacer que este campo apunte a la parte privada
		de la estructura que será ubicada por la función que
		originalmente creaba la estructura pública.  Es
		importante que este campo no sea llamado
		<structfield>private</structfield>, se trata de
		una palabra reservada de C++ y creará problemas cuando
		el archivo de encabezado sea usado desde programas
		fuentes C++ &mdash; mejor llámalo 
		<structfield>priv</structfield>.  Por supuesto, este
		tipo de cambios sólo funcionará si el antiguo campo
		puntero solamente era usado para propósitos internos;
		si los usuarios de la biblioteca habían tenido acceso
		a dicho campo para cualquier propósito, será necesario
		buscar otro campo o buscar una solución diferente.
      </para>

      <para>
		Si la estructura original fue derivada de
	<structname>GtkObject</structname> y no hay campos punteros
	que puedan ser reemplazados, puedes usar la facilidad
	de datos de objetos de GTK+.  Esto permite asociar punteros
	a datos arbitrarios a objetos.  Usa la función
	<function>gtk_object_set_data()</function> para adjuntar
	valores o estructuras a un objeto y cuando requieras usarlos
	la función <function>gtk_object_get_data()</function> 
	permitirá recuperar dichos valores.  Esto puede ser empleado
	para adjuntar una estructura privada a un objeto GTK+.
	Esto no es tan eficiente como el enfoque anterior, pero podría
	no importar para el dominio particular de la aplicación.  Si
	los datos serán accedidos frecuentemente, se pueden usar
	quarks en vez de cadenas para agregar y obtenerlos a través
	de las funciones
	<function>gtk_object_set_data_by_id()</function> y
	<function>gtk_object_get_data_by_id()</function>, 
	respectivamente.
      </para>

    </sect2>
  </sect1>

  <!-- Modifying Other People's Code -->

  <sect1 id="modify">
    <title>Cómo modificar el código de otros</title>

    <para>
	  GNOME es un proyecto de equipo, así las contribuciones de
	  código a programas de otras personas siempre son apreciadas.
	  Sigue los siguientes lineamientos cuando modifiques el código
	  de otra persona.
    </para>

    <!-- General Etiquette -->

    <sect2 id="etiquette">
      <title>Etiqueta general</title>

      <para>
		Siga el mismo estilo de indentación usado en el código 
		original.  El código original perdurará durante más tiempo
		que el que le pueda dedicar, mantener las 
		contribuciones consistentes respecto a la indentación
		es más importante que forzar su estilo de indentación
		en el código.
      </para>

      <para>
		Aunque sus parches pueden implementar una 
		funcionalidad muy llamativa, es muy molesto para el 
		autor tener que reindentar el código antes de aplicar
		un parche al código principal.  Así, si el código
		original luce como:

      <programlisting>
int
sum_plus_square_of_indices (int *values, int nvalues)
{
	int i, total;

	total = 0;

	for (i = 0; i &lt; nvalues; i++)
		total += values[i] + i * i;

	return total;
}</programlisting>

	entonces no agregues una función que luce como:

	<programlisting>
int sum_plus_cube_of_indices(int *values, int nvalues) {
  int i,total;

  total=0;

  for (i=0;i&lt;nvalues;i++)
    total+=values[i]+i*i*i;

  return total;
}</programlisting>

	En el segundo ejemplo, la indentanción y ubicación de las
	llaves no coincide con el código original, no hay espacios 
	alrededor de los operadores y el código no se parecerá
	al original.  Sigue el estilo de programación del autor
	original del programa y los parches que envías tendrán una mejor
	oportunidad de ser aceptados.
      </para>

      <para>
		No repares errores con artilugios o hacks rápidos; repáralo
		correctamente.  Tampoco añadas características como hacks o
		con código que no sea extensible; es mejor rehacer el 
		código original para que sea extensible y luego agrega
		la nueva característica, utilizando el código como 
		estructura.
      </para>

      <para>
		La limpieza de código siempre es bienvenida; si encuentras
		trozos de código feos y sucios en GNOME, será muy
		apreciado si envías parches que hagan el código más
		agradable y fácil de mantener.
      </para>

      <para>
		Como siempre, asegúrate de que el código que contribuye compila
		sin ningún tipo de aviso, que tenga los prototipos correctos
		y que sigan las directrices de este documento.
      </para>
    </sect2>

    <!-- Documenting Your Changes -->

    <sect2 id="document">
      <title>Cómo documentar los cambios</title>

      <para>
		GNOME utiliza los archivos &ChangeLog; estándar de GNU para
		documentar los cambios al código.  Cada cambio que 
		efectúes a un programa <emphasis>debe</emphasis> ser
		acompañado por una registro en el &ChangeLog;.  Esto
		permite a las personas leer la historia de cambios 
		del programa de una manera sencilla.
      </para>

      <para>
		Si usas &Emacs;, puede agregar las líneas al 
		&ChangeLog; presionando «C-x 4 a».
      </para>

      <note>
	<para>
		Si conoces la forma de realizarlos para otros editores
		populares, agradeceremos que nos lo hagas saber para
		expandir este documento.
	</para>
      </note>

      <para>
	Cada registro en el &ChangeLog; tiene un forma general:
	<programlisting>
1999-04-19  J. Random Hacker  &lt;jrandom@foo.org&gt;

	* foo.c (some_function): Changed the way MetaThingies are
	frobnicated.  We now use a hash table instead of a linked list to
	look MetaThingies up.
	(some_other_function): Support the MetaThingies hash table by
	feeding it when necessary

	* bar.c (another_function): Fixed bug where it would print "Take
	me to your leader" instead of "Hello, World".

1999-04-18  Johnny Grep  &lt;grep@foobar.com&gt;

	* baz.c (ugly_function): Beautified by using a helper function.</programlisting>
      </para>

      <para>
		Si agregas una nueva función a una biblioteca, escribe
		la referencia necesaria y la documentación de programación.
		Puedes escribir una referencia a la documentacion 
		en línea usando el formato de comentarios descrito en
		<filename>gnome-libs/devel-docs/api-comment-style.txt</filename>.
		Si usas &Emacs;,
		<filename>gnome-libs/tools/gnome-doc/gnome-doc.el</filename>
		provee un acelerador que puede ser empleado para añadir
		una plantilla de documentación al programa.
      </para>
    </sect2>

    <!-- Changing Code on CVS -->

    <sect2 id="change-cvs">
      <title>Cómo actualizar en CVS</title>

      <para>
		Si tienes acceso de escritura en el repositorio CVS de GNOME,
		debes seguir algunas políticas adicionales.  Ya que estás
		trabajando en la copia maestra de los fuentes, debes tener
		especial cuidado.
      </para>

      <para>
		Si estás reparando algo en un programa que está en el CVS
		o si estás añadiendo una funcionalidad allí, y si no has
		estado trabajando en dicho programa por un período largo
		de tiempo, pregunta al autor original antes de aplicar
		sus parches.  Generalmente está bien formular estas
		preguntas en la lista de correo
		<filename>gnome-devel-list</filename>.
      </para>

      <para>
		Una vez que el autor del programa te indique como un
		&lsquo;contribuyente frecuente&rsquo;, puedes comenzar 
		aplicar los parches sin previo consentimiento. Si
		quieres aplicar una reorganización mayor del código,
		debieras preguntar primero.
      </para>

      <para>
		Algunos módulos en el CVS tienen rama estable y de
		desarrollo.  Normalmente el desarrollo debiera ir
		en la rama HEAD en el CVS, y la rama estable debiera
		mantenerse separadamente.  Generalmente no se añaden
		nuevas características a las rama estable; sólo
		se reparan errores.  Repara el error a la rama estable
		y pregunta al autor principal sobre la política para
		mezclar parches en la rama de desarrollo; algunos
		autores prefieren hacerlo por lotes, mientras hay otros
		que prefieren mezclarlos inmediatamente.
      </para>

      <para>
		Si trabajas en una característica experimental que
		podría estropear mucho código, crea una rama en el CVS
		y realiza los cambios allí.  No los mezcles en la rama
		principal de desarrollo hasta que te encuentres
		razonablemente seguro que funcionará correctamente y que
		se integrará bien dentro del resto del código.  El uso de
		una rama para trabajo en características experimentales
		te permitirá evitar interrumpir el trabajo de otros
		desarrolladores.  Pregunte al autor principal antes de
		mezclar tu rama y traer sus cambios a la parte principal 
		del árbol.
      </para>

      <para>
		Como siempre, agrega un registro en el &ChangeLog; 
		cuando realices un cambio.  Algunos autores tienen la
		política de rechazar, correctamente, los cambios que 
		no tienen tal registro.
      </para>

      <para>
		Algunas veces existen diferentes políticas para los módulos,
		verifica si el módulo contiene un archivo
        <filename>README.CVS</filename>.  Si es así, lee ese archivo
		antes de realizar cambios.
      </para>

      <!-- Branches and Tags -->

      <sect3 id="branches">
	<title>Ramas y marcas</title>

	<para>
	  Tenemos una convención para nombrar las ramas y marcas o
	  puntos de una rama en el repositorio de CVS de GNOME. 
	  Las marcas deben ser definidas después que se libera cada
	  nueva version y deben ser de la forma
	  «MODULE_MAJOR_MINOR_MICRO», por ejemplo,
	  «GNOME_LIBS_1_0_53».  Los puntos de una rama
	  deben ser de la forma «MODULE_BRANCH_ANCHOR», 
	  como en «GNOME_LIBS_1_0_ANCHOR».  Finalmente, 
	  una rama raíz en este punto debiera ser de la forma
	  «module-branch», por ejemplo, 
	  «gnome-libs-1-0».  Usa esta convención cuando
	  crees marcas, puntos de una rama y ramas.
	</para>
      </sect3>

      <!-- Additional CVS Policies -->

      <sect3 id="cvs-policies">
	<title>Políticas adicionales del CVS</title>

	<para>
	  CVS no proporciona un manera preconstruida para renombrar archivos
	  o moverlos a otros directorios.  Debiera planificar 
 	  cuidadosamente el árbol del repositorio de tal forma que evite
	  mover o renombrar archivos.
	</para>

	<para>
	  En el caso que debas mover o renombrar un archivo en el CVS,
	  <emphasis>NO EJECUTES</emphasis> «cvs remove»
	  y luego «cvs add».  Si lo haces, los archivos
	  «nuevos» perderán la capacidad de seguir su
	  historial de cambios, ya que desde el punto de vista de CVS
	  serán archivos completamente nuevos en su revisión
	  inicial.  Un objetivo del repositorio CVS de GNOME es 
	  poder seguir la historia de los fuentes de manera 
	  precisa desde el inicio.
	</para>

	<para>
	  <emphasis>Por favor</emphasis>, pregunte al mantenedor
	  del CVS, esto es, una persona conocida con acceso shell
	  a la máquina con CVS, para realizar la cirugía necesaria
	  para mover los archivos por ti.  Esto requiere 
	  conocimiento de la forma en que funciona CVS y debe ser
	  hecho muy cuidadosamente.  La recuperación de un error de
	   «cvs add/remove» es una tarea muy desagradable;
	  Si mueves archivo en esta forma equivocada, un mantenedor
	  del CVS, quien tendrá que ir a reparar y realizar el trabajo
	  sucio, reclamará las penas del infierno.  Así es que mejor
	  pregunta por una persona que pueda mover los archivos por
	  ti.
	</para>
      </sect3>
    </sect2>
    
  </sect1>

  <!-- Maintaining a Package -->

  <sect1 id="maintain">
    <title>Cómo mantener un paquete</title>

    <para>
	  Un mantenedor de paquete es una persona que se preocupa de
	  liberar versiones, integrar cambios de otras personas y,
	  en general, ser responsable de un paquete.  Durante el
	  período de vida de un paquete, éste puede cambiar de 
	  mantenedores, por ejemplo, una persona que pierde interés
	  o que ya no puede dedicarle tiempo suficiente como mantenedor.
    </para>

    <para>
	  En conformidad con los Estándares de programación de GNU, GNOME
	  usa GNU Autoconf para manejar la portabilidad  y GNU Automake
	  para crear makefiles.  Automake hace especialmente fácil
	  construir paquetes correctos, así que si eres un mantenedor
	  de paquetes, debieras aprender como usarlo.  Autoconf y 
	  Automake tienen muchas áreas truculentas, así que siéntete
	  libre de pedir ayuda en las listas de desarrollo de GNOME
	  si tienes preguntas sobre la forma correcta de construir
	  makefiles para tu paquete.
    </para>

    <para>
	  Un número de personas regularmente contribuye con traducciones
	  localizadas de los catálogos de mensajes en los paquetes de
	  GNOME.  Para mantener las traducciones actualizadas tanto como
	  sea posible, los mantenedores deben coordinarse con los 
	  traductores para que estos últimos puedan actualizar las
	  traducciones a tiempo cuando se va a liberar una nueva 
	  versión del paquete.  Una buena forma de notificar a los
	  traductores consiste en enviar un mensaje a
      <email>gnome-i18n@gnome.org</email> con suficientes
	  días de anticipación.  Esto les permitirá actualizar sus
	  respectivas traducciones a tiempo para puedan ser incluidas
	  en la siguiente versión liberada.
    </para>
  </sect1>

  <!-- Memory Leaks Agenda -->

  <sect1 id="memory-leak">
    <title>¿Por qué preocuparse por la pérdida de memoria?</title>

    <para>
	  Échale un vistazo a la lista de errores de Mozilla y una cosa es
	  clara: el nuevo código que entra a Mozilla no es (o no ha sido)
	  verificado suficientemente por pérdida de memoria y problemas
	  de acceso.
    </para>
  
    <para>
	  Las pérdidas de memoria son malas por varias razones:

      <itemizedlist>
	<listitem>
	  <para>
		Se comerá el área de intercambio lentamente. A la larga tu
		programa, o hasta tu máquina sucumbirán.
          </para>
          <para>
		Nadie quiere que su programa o biblioteca adquiera la 
		reputación de ser una porquería sólo porque uno ha sido un
		vago.  Déjaselo a las personas en Redmond.
		</para>
	</listitem>

	<listitem>
	  <para>
		Ocultan el mal uso de la memoria.  Si olvidas liberar la
		memoria, no hay forma de atrapar las lecturas y
		escrituras a esos trozos de memoria.  Si, posteriormente,
		reparas la pérdida, una parte completamente distinta
		del programa podría fallar.
      </para>
	</listitem>

	<listitem>
      <para>
		Cuando se usan verificadores automáticos de memoria,
		nadie quiere ver 600 problemas, de los cuales 500
		se encuentran en las bibliotecas de soporte. Lo que
		deseas saber es que estaba todo limpio antes que comenzara
	    el caos, y por lo tanto, esos problemas te corresponde a ti
		arreglarlos.
	  </para>

	  <para>
		Este es uno de los problemas de Mozilla actualmente: 
		pierde memoria sin parar así que ¿cómo vas a saber si has 
	    contribuido al problema?
          </para>
	</listitem>
      </itemizedlist>
    </para>
 
    <sect2 id="memory-advice">
      <title>Algunos consejos contra la pérdida de memoria.</title>

      <para>
        <itemizedlist>
          <listitem>
	    <para>
	      Usa «<symbol>const</symbol>» donde sea posible (para 
		  punteros obviamente).
        </para>
	    <para>
  	      Si un argumento es «<symbol>const</symbol>», entonces 
		  indudablemente la función llamada no liberará la memoria por 
		  ti.
        </para>
	    <para>
		  Si el tipo de resultado de una función es 
		  «<symbol>const</symbol>», entonces
		  claramente no eres responsable por liberarlo. 
		  <emphasis>Probablemente</emphasis> lo será para un resultado
		  distinto de «<symbol>const</symbol>» (que no sea un entero 
		  o algo similar).
        </para>
	    <para>
		  Fíjate en que, desafortunadamente, esto no funciona muy bien
		  con los objetos que cuentan referencias.  Funciona bien
		  con cadenas.
        </para>
	    <para>
		  Dado que C usa llamadas por valor, no tiene sentido
		  aplicar «<symbol>const</symbol>» a tipos 
		  <symbol>int</symbol>, <symbol>double</symbol> y similares.
         </para>
	  </listitem>

	  <listitem>
	    <para>
	      <emphasis>Documenta las responsabilidades.</emphasis>
            </para>
	    
	    <itemizedlist>
	      <listitem>
		<para>
			 Si una función toma la propiedad de un objeto/referencia,
			 sé explícito acerca de ello.
                </para>
	      </listitem>

	      <listitem>
		<para>
			 Indica siempre si el que llama a la función debiera
			 liberar/desreferenciar los resultados.
                </para>
	      </listitem>

	      <listitem>
		<para>
		  Documenta <emphasis>cómo</emphasis> entregar la 
		  memoria: unref, free, g_free, ...
                </para>
	      </listitem>
	    </itemizedlist>
	  </listitem>

          <listitem>
	    <para>
	      <emphasis>Se cuidadoso cuando uses copiar-y-pegar.</emphasis>
            </para>

	    <para>
			  El proceso de cortado y pegado no mejora el código, al 
			  contrario de lo que creen muchos programadores.  Primero,
			  mira el código y si intenta producir muchas copias, quizás
			  necesite una función ayudante o nexo. <!-- FIXME: mejor 
			  traducción de helper -->
            </para>
	  </listitem>

          <listitem>
	    <para>
	      <emphasis>Libera todo antes de salir.</emphasis>
        </para>
        <para>
		  Esto lleva tiempo, así que quizás debieras hacerlo 
		  sólo dentro de una condición.
        </para>  
	    <para>
		  El motivo de este consejo es que los verificadores de memoria
		  toman tiempo en determinar entre una pérdida que tu conoces 
		  y no te preocupan, y las otras pérdidas.
        </para>
	  </listitem>

	  <listitem>
	    <para>
	      <emphasis>No dejes punteros sueltos en tus estructuras de 
		  datos.</emphasis>
        </para>

	    <para>
		  Asigna <symbol>NULL</symbol> o 
		  <symbol>(void *)0xdeadbeef</symbol> para los miembros 
		  liberados a menos que vayas a liberar la estructura a la 
		  que pertenecen.
        </para>
	    
	    <para>
		  Los punteros sueltos tienen la mala tendencia a ocultar pérdidas
		  de memoria.
	    </para>
	  </listitem>

	  <listitem>
	    <para>
	      <emphasis>Ejecuta el nuevo código en un ciclo 1 millón de 
		  veces.</emphasis>
            </para>

	    <para>
		   Si pierdes memoria, lo sabrás &mdash; sólo sigue al proceso con
		   <command>top</command> en otra ventana.  Podrías querer
		   especificar a top el <symbol>PID</symbol>
		   del proceso con la opción <parameter>-p</parameter>.
            </para>
	  </listitem>

	  <listitem>
	    <para>
	      <emphasis>Repáralo ahora, no después.</emphasis>
            </para>

	    <para>
		  No escribas una porquería de código; más temprano que 
		  tarde te pesará.
        </para>
	  </listitem>
	</itemizedlist>
      </para>
    </sect2>
  </sect1>
</article>