Translate

lunes, 17 de diciembre de 2012

Ayuda para entrevistas laborales de desarrollo de software.


Roque Manuel Rueda Anastacio.
10/12/12


Tabla de versiones

Versiones
Versión
Fecha
Autor
Comentario
0.1
10/12/2012
Roque Rueda
Creado

Objetivo

Ser un apoyo fácil para incrementar acertar el mayor numero de preguntas durante el desarrollo de entrevistas técnicas de desarrollo de software.

Introducción

Este documento proporciona un conjunto de conceptos y mi punto de vista particular así como ejemplos para el apoyo durante las entrevistas laborales para vacantes relacionadas con desarrollo de software. Se realiza con la experiencia obtenida de entrevistas previas. En la mayoría de las entrevistas de las que yo he sido parte; usualmente se realizan las mismas cuestiones además, debido a que algunos de los entrevistadores usualmente son desarrolladores de software, tienen un conocimiento práctico en lenguajes sin embargo sorprendentemente algunos de ellos pueden tener nociones equivocadas de los conceptos más básicos.

1. Programación Orientada a Objetos

El termino programación Orientada a Objetos, este termino que debiera ser Análisis y Diseño Orientado a Objetos, se refiere a tener una perspectiva de objetos (cosas, conceptos o entidades) para el dominio del problema y su solución lógica. Ahora bien el dominio del problema es la problemática que pretende solucionar (el problema por el cual se debe desarrollar un producto de software) y la solución lógica sera la especificaciones que debe cumplir el sistema para solucionar la problemática. En un Análisis Orientado a Objetos, los “objetos” son descritos en el dominio del problema, mientras que en el Diseño esos “objetos” se convierten en objetos lógicos de software que finalmente serán implementados en un lenguaje orientado a objetos, por ejemplo Java o C#. La duda que surge entonces ¿Qué es un Objeto? Un objeto es una pieza de software que se ejecuta realizando operaciones de un programa. Un objeto se define como una instancia de una clase ya que la clase es la definición del los atributos y comportamiento del objeto. Mientras que el objeto es en tiempo de ejecución el elemento que realiza las acciones. Y eso no lleva a otra duda ¿Qué es una clase? Una clase es un documento (podemos decir código) que define como se menciona anteriormente los objetos, podemos decir que es una orientación a los datos ya que la clase define que datos contiene el objeto y que operaciones puede realizar el objeto con los datos sin embargo esto puede causar confusión. Una analogía es que la clase es el plano arquitectónico y el objeto es la casa construida. Los siguientes elementos son conceptos que intervienen en un diseño Orientado a Objetos.

Diagrama de un objeto
Figura 1. Diagrama de un objeto

1.1. Encapsulamiento

El encapsulamiento es la característica que un objeto tiene de ocultar su información a los otros objetos, cualquier otro objeto solo se puede acceder a los datos mediante la invocación de métodos. El encapsulamiento brinda que los cambios en los datos de los objetos se realicen de manera controlada y también dan la capacidad de ignorar la implementación de las operaciones que realiza el objeto centrándose solo en los valores resultado. Esto se podría ejemplificar con un automóvil el cual al pisar el acelerador se espera que incremente su velocidad el como sea llevada a cabo la operación (motor, combustible, ignición), para el cliente de la operación solo le interesa que se incremente la velocidad no como se lleve a cabo ahí es donde el encapsulamiento resulta de utilidad.

1.2. Abstracción

Es el proceso en el que los datos se definen para representar una imagen o forma que permita obtener un significado que existe en el dominio del problema, sin entrar a un nivel de implementación. La abstracción permite descomponer la problemática en partes mas pequeñas. Permitiéndonos dividir la implementación (como se llevara a cabo) de la definición (que hay que llevar a cabo).

En un lenguaje como Java una clase es la definición del comportamiento y los datos. Una clase no se puede utilizar directamente. Un objeto es la instancia de la clase y es el objeto el que realiza las operaciones.

1.3 Polimorfismo

Es la capacidad que tienen las variables de contener objetos de diferentes clases, usualmente se dice que los objetos adquieren diferentes formas sin embargo son las variables que los contienen las que pueden adquirir valores de diversas clases. Si una clase Hijo es una subclase de la clase Padre entonces un método que espere un parámetro un objeto de clase Padre también puede ser invocado con un parámetro de la clase Hijo. El polimorfismo se da en lenguajes como Java o C# de 4 maneras la clase padre, la interfaz que implementa, la clase Object y el mismo.

Ejemplo:
public interface Person{
void comer();
}

public class Padre implements Person
{
public void saludar(String nombre){
System.out.println(“Hola desde padre: ” + nombre);
}

public void comer(){
System.out.prinln(“Comiendo padre... c:”);
}
}

public class Hijo extends Padre{
public String toString(){
// Metodo de la clase Object
return “Hola soy un hijo”;
}
}

/* Ejemplo de codigo */

public static void main (String[] args){
// Digamos que queremos crear un objeto Padre
Padre p = new Padre();
// Al existir herencia se crea una relación es un (is a)
// por lo tanto se puede decir que un Hijo es un Padre
p = new Hijo(); // se asigna un hijo en una
// variable de tipo Padre

p.saludar(“Roque”); // p contiene un hijo
// ya que hereda los metodos se puede invocar el metodo
// saludar de la clase padre

Persona per = p; // Se asigna la variable per de tipo
// Persona el valor contenido en la varable p la cual
// apunta a un objeto de tipo Hijo el cual es un Padre
// debemos recordar que tambien al implementar la interfaz
// se obtiene la relacion es un por lo que se puede decir
// que un Hijo tambien es una Persona.

per.comer(); // Esto es legal!

System.out.println(per); // El metodo println espera un
// parametro de tipo Object y ya que todo es un objeto
// esta es aceptada

Hijo h = (Hijo) per; // Esto es riesgoso pero es legal
// la conversion hacia arriba en la jerarquia de clases
// no requiere el cast

}

1.4. Herencia

Permite que las clases sean basadas en otras. Si una clase “A” hereda de otra clase llamada “B” se dice que la clase “A extiende a B”. Por ejemplo se puede definir una clase base que almacene un archivo y posteriormente esa clase sea extendida por otra clase para que se notifique al usuario de un archivo almacenado (agregar nueva funcionalidad).

1.5 Delegación

Delegación es cuando cedes la responsabilidad de alguna tarea a otra clase o método. Si se requiere utilizar esa funcionalidad en otra clase pero no se quiere cambiar la funcionalidad se utiliza delegación en lugar de herencia (se prefiere la agregación/composición a la extensión/herencia).

1.6 Composición

La composición se refiere a la representación de una familia de comportamiento mediante un conjunto de objetos. Se programa utilizando una interfaz y cualquier clase que implemente esta interfaz podrá ser definida.
En la composición los objetos que componen el objeto compuesto dejan de existir tan pronto como el objeto compuesto lo haga.

1.7 Agregación

La agregación permite invocar el comportamiento de otra clase sin la limitacion de tiempo de vida de ese comportamiento. Se puede decir que la agregación es cuando el comportamiento es invocado desde un objeto pero este no deja de existir cuando el objeto es terminando. Ejemplo: Salida estandar.
public class Parte {
int sumar(int numero, int otroNumero) {
return numero + otroNumero; // Sumar
}
}
public class Composicion {
Parte parte;
Composicion() {
parte = new Parte();
}
void imprimirSum(int numero, int otroNumero) {
System.out.println(parte.sumar(numero, otroNumero));
}
}
/* Ejemplo de codigo */

public static void main (String[] args) {
Composicion c = new Composicion ();
c.imprimirSum();
// El objeto parte deja de existir en cuanto el objeto
// composición lo hace
}
// Agregación
public class Parte2 {
int sumar2(int numero, int otroNumero) {
return numero + otroNumero; // Sumar
}
}
public class Agregacion {
Parte2 parte;
void imprimirSum(int numero, int otroNumero) {
if(parte != null) {
System.out.println(parte.sumar(numero, otroNumero));
}
}
public void setParte(Parte2 parte) {
this.parte = parte;
}
}
/* Ejemplo de codigo */

public static void main (String[] args) {
Agregacion a = new Agregacion ();
Parte2 p = new Parte2 ();
a.setParte(p);
a.imprimirSum();
// El objeto parte puede continuar existiendo después de su uso
}

2. Interfaces y clases Abstractas

Una clase se compone de dos partes la interfaz y la implementación. Entendemos por interfaz la definición (firma de métodos) y la implementación como el código que realiza la ejecución de las acciones. ¿Qué beneficios se obtienen de las interfaces? Un diseño por contratos, se dice por contratos ya que se asume que ambas partes de la transacción comprenden que acciones generan que comportamiento y cumplen ese contrato.
Una interfaz permite generar un diseño por contratos, la diferencia entre una clase abstracta y una interfaz es que una clase abstracta puede contener implementación mientras que en una interfaz unicamente se cuenta con la definición de la firma de los métodos. Es por eso que en una clase abstracta existe herencia mientras que en una interfaz solo existe implementación.
  1. Cohesión y Acoplamiento

Un sistema debe contar con una alta cohesión, la cohesión es la medida en la que las clases están relacionadas y que tan centrada son las responsabilidades de las clases. Un elemento es cohesivo a medida que cambia el elemento entero cuando el sistema necesita cambiar. Un diseño orientado a objetos es beneficioso el asignar responsabilidades para obtener una cohesión alta. Por lo que se deben evitar clases que tienen diferentes responsabilidades.
Dos elemento están acoplados a medida en el que los cambios de una parte involucran cambios en el otro elemento. El acoplamiento entre los elemento es un conductor de los cambios.
Se debe hablar solo a los amigos inmediatos.
Las entidades de software como las clases, módulos y funciones deben ser abiertos a extensiones pero cerrados a modificaciones. Este principio nos indica que se debe crear código que pueda aceptar nuevas extensiones sin que se deba modificar el código con el que ya se cuenta.
Un ejemplo es cuando una clase llama internamente a una clase abstracta para obtener cierto comportamiento. En tiempo de ejecución se provee de la implementación de la clase abstracta los que nos permite posteriormente proporcionar una nueva implementación para obtener nuevo comportamiento del código ya existente.