Hola
Si tenéis algún problema con una aplicación Android para escribir ficheros en un dispositivo conectado por USB (pen drive, disk memory, hard drive, etc..) o para descargar ficheros directamente sobre un dispositivo conectado por USB entonces lo mas seguro es que sea por un problema de permisos.
Los permisos para escribir ficheros en un USB se declaran en el fichero /system/etc/permissions/platform.xml
Localizar la etiqueta donde pone:
<permission name="WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_rw" /> <-- PERMISOS PARA ESCRIBIR EN DISCO DURO
</permission>
y añade de la siguiente manera
<permission name="WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_rw" />
<group gid="media_rw" /> <-- PERMISOS PARA ESCRIBIR EN USB
</permission>
Si no existe WRITE_EXTERNAL_STORAGE entonces crea la etiqueta entera.
Reinicia el sistema operativo y ya debería dejarte escribir en un USB.
Para editar el fichero platform.xml solo necesitas un edictor de texto.
Para salvar los cambios necesitas entrar como root. Si tienes problemas para esto puedes usar los siguientes pasos:
1 Bajate del Play Store un emulador de terminal.
2 Ejecutalo y entra como root con el comando "su":
terminal$> su
terminal#> <-- Como ves has pasado de $ a #, eso es que ya eres root
3 Ahora salva el fichero platform.xml por si hay algun error y hay que volver a la version anterior
terminal#> mv /system/etc/permissions/platform.xml /system/etc/permissions/platform.xml.ori
4 Copia el fichero platform.xml con la modificación en la etiqueta WRITE_EXTERNAL_STORAGE en su lugar (supongamos que lo editaste en el directorio /sdcard/platform.xml)
terminal#> mv /sdcard/platform.xml /system/etc/permissions/platform.xml
Espero que esto os sirva.
Un saludo
miércoles, 31 de julio de 2013
viernes, 21 de junio de 2013
El desgaste de un mal ritmo
Uno de los factores que afecta a la productividad de un programador es llevar un ritmo que no es el adecuado. Cuando un programador lleva un mal ritmo?
- Si las tareas no están claras. Si el programador no tiene clara cual es su tarea seguro que la terminara muy rápido y el resto del tiempo no sabrá que hacer.
- Si el ritmo de trabajo es pausado. Si se esta en un mantenimiento o en sistema de resolución de incidencias entonces el trabajo entra en forma de grifo (a veces son gotas y a veces son autenticas cataratas) y muy descentralizado (la tarea de hoy puede no tener nada que ver con la de mañana) pero si es un desarrollo de una aplicación entonces el programador necesita ver profundidad en su trabajo. Si a un programador se le da el primer trabajo que se le ocurra al jefe entonces el programador cogerá un mal ritmo.
Lo que hay que evitar por todos los medios es que el programador se pueda quedar desocupado. Si el programador esta desocupado empecerá a pensar cosas como ¿estoy perdiendo el tiempo? ¿Deberia hablar con el jefe? ¿..? (seguro que esto te suena) etc.. y no estará concentrado en la tarea lo cual le hace no solo hacer la tarea mas lenta si no que estará predispuesto a hacer las cosas peor.
Es mejor bombardear al programador con curro que tenerlo haciendo cualquier cosa.
martes, 18 de junio de 2013
Desarrollo enmarcado
La mayor técnica de desarrollo en equipo que se usa en las
empresas (no por su efectividad si no por su simplicidad) es empezar a echar líneas
de código a ver lo que sale.
Si las cosas se piensan mejor, se pueden pensar una serie de
directrices que deben seguir los programadores ya que “la traducción” del
negocio a líneas de código se hace con una relación más o menos mecánica.
Por ejemplo, si se tiene que hacer una aplicación que guarde
informes que siempre tienen tres partes bien diferenciadas entonces:
- A ver lo que sale: Se hace la división de alto nivel del trabajo que el responsable considere oportuno (tu las ventanas, tu guardar en base de datos, tu la ventana de informe de gasto que tiene una lógica mas compleja, etc…) y cada programador se pone a la tarea. Las fronteras van a apareciendo a medida que se desarrolla y se resuelven como se puede
- Enmarcado: Se considera todo el problema sin dividirlo y se define una base que al crecer puede dar una solución al problema. Primero se desarrolla un CORE que crea un informe base que es común y es muy configurable para poder dotar a cada informe de su forma definitiva. Cada programador parte de ese CORE para implementar su tarea.
Mucho ojo con el desarrollo enmarcado ya que conceptualmente
todo es muy bonito pero los problemas de verdad (los que hacen perder tiempo o
pueden tumbar una idea) aparecen siempre a bajo nivel. Se debe tener una CORE
maduro antes de empezar a programar y uno de los programadores que participaron
en el CORE debe de hacer uno de los informes. Esto último es importante ya que
por muy bien que se piense el marco de trabajo cuando se divida el trabajo (dentro
del marco) empezaran a aparecer problemas y habrá que ajustar el marco. También
es importante elegir el (o los) informe que tiene que hacer el programador del
CORE, tiene que ser lo mas representativo posible.
lunes, 22 de abril de 2013
Codigo probable
Muchas veces se ha terminado una tarea y se pide que se pruebe el codigo. Que el codigo hay que probarlo es una cosa que se debe de tener en cuenta desde el principio de desarrollo. Un codigo es ”probable” cuando se puede hacer un test unitario para probarlo.
El gran problema de este axioma son las dependencias de otros sistemas. Por ejemplo, supongamos una funcion como la siguientes:
Private ManagerBD daoClientes;
Private ManagerWS webServicesClientes;
Public List buscarClientesValidos (Date inicio, Date fin) {
List todosClientesEntreFechas = daoClientes.buscarClientes (inicio, fin);
List resultado = new ArrayList();
for (Cliente cliente: todosClientesEntreFechas ){
if (webServicesClientes.esValido (cliente))
resultado.add (cliente);
}
return resultado;
}
public void setWebServicesClientes (ManagerWS webServicesClientes){
this. webServicesClientes = webServicesClientes;
}
public void setDaoClientes (ManagerBD daoClientes){
this. daoClientes = daoClientes;
}
El metodo buscarClientesValidos es completamente probable ya que las dependencias a otros sistemas (BD y web services) son facilmente remplazables. En el test solo tendrias que usar los set para cambiar las instancias de ManagerBD y ManagerWS por unas que sean mocks y devuelvan lo que tu quieras.
Pero si por ejemplo tienes en el metodo algo asi
Public List buscarClientesValidos (Date inicio, Date fin) {
List todosClientesEntreFechas = daoClientes.buscarClientes (inicio, fin);
List resultado = new ArrayList();
for (Cliente cliente: todosClientesEntreFechas ){
if (WSInstancia.esValido (cliente))
resultado.add (cliente);
}
return resultado;
}
Es decir, un metodo estatico de una clase que no tienes instanciada a nivel de clase entonces este metodo no es probable. Lo puedes hacer problable sacando la llamada a un metodo
Public List buscarClientesValidos (Date inicio, Date fin) {
List todosClientesEntreFechas = daoClientes.buscarClientes (inicio, fin);
List resultado = new ArrayList();
for (Cliente cliente: todosClientesEntreFechas ){
if (esValido (Cliente cliente))
resultado.add (cliente);
}
return resultado;
}
Public boolean esValido (Cliente cliente){
return WSInstancia.esValido (cliente);
}
Ahora el metodo es probable de nuevo ya que solo tienes que que crear una instancia de la clase y sobreescribir el metodo esValido por un metodo que devuelva lo que tu quieras.
La clave de la validez de las pruebas es que NO HAY QUE TOCAR CODIGO del metodo que estas probando. Si has modificado una linea del codigo, aunque sea lo mas simple del mundo, tienes que volver a problarlo todo.
Otra cosas importante para probar es tener el entorno para probar preparado desde un principio. Es decir, para hacer la prueba de la clase que contenga el metodo buscarClientesValidos tienes que instanciarla y si para ello tienes que pasarle variables de iniciacion compleja entonces tienes que tenerlas preparadas desde el principio de la prueba. No puedes crear un entorno distinto para cada prueba porque perderias mucho tiempo.
Otra cosas importante para probar es tener el entorno para probar preparado desde un principio. Es decir, para hacer la prueba de la clase que contenga el metodo buscarClientesValidos tienes que instanciarla y si para ello tienes que pasarle variables de iniciacion compleja entonces tienes que tenerlas preparadas desde el principio de la prueba. No puedes crear un entorno distinto para cada prueba porque perderias mucho tiempo.
viernes, 19 de abril de 2013
Apunta las cosas
Una practica que solo un 5% de los informaticos llevan a cabo y que deberian hacer el 100% es tener algun sistema para apuntar lo que tienes que hacer, lo que estas haciendo, información que te aportan, etc.. es decir, TODO.
Ya sea una dirección IP donde esta la aplicación que tienes que usar, las tareas que te ha asignado el jefe, las claves de algun servidor, etc.. APUNTALO TODO.
Una de las cosas que peor imagen da y que va a retrasar tu crecimiento profesional es olvidar cosas (tareas, reuniones, etc..) o parte de esas cosas. Si las olvidas por completo da la impresión de que no te importa y si haces peor las cosas por olvidar partes de esas cosas entoces da la impresión de ser incompetente.
Tienes que elegir una manera de notación de tal manera que tampoco te lleve mucho tiempo anotar cosas y acceder posteriormente a ellas.
Si el sistema es digital (una pagina web por ejemplo) tendras mas dinamismo a la hora de modificar/ampliar la informacion y a la hora de mostrarle ha alguien la información. Yo te recomiendo la aplicación mediawiki. (Consejo para la mediawiki: si quieres que solo un usuario registrado pueda modificar los apartados entonces incluye en el fichero de localsettings.php la linea $wgGroupPermissions['*']['edit'] = false;).
Apuntarlo todo tambien es muy util cuando un desarrollo se termina y aparecen tareas que no se tienen en cuenta al principio:
- Poner comentarios en codigo.
- Hacer un informe resumen a algun jefe de lo que se ha hecho.
- Comentar un alguna aplicación de control de tareas lo que se ha hecho.
- Etc..
Si tienes apuntado lo que has ido haciendo y como lo has hecho entonces te evitaras el problema de recorda como has hecho unas cosas e incluso de tener que escribir nada ya que puedes resolver las tareas anteriores copiando lo que has ido escribiendo. Como mucho tendras que escribir texto para darle algo de forma pero poco mas.
jueves, 14 de marzo de 2013
No JNI
Cuando se
desea usar una librería del sistema operativo (.dll, .so, etc…) desde una aplicación Java la solución que nos
aporta el lenguaje Java es usar JNI y los métodos “native”. La arquitectura es
la siguiente:
Las
librerías se cargan al solo una vez y no es posible eliminarlas ni volver a
cargarlas durante la ejecución de la aplicación Java. Yo quiero proponer otra
alternativa (a la que llamaremos por control) y luego comprarla con JNI para
ver cual sería mejor.
Por la parte
de C, lo que propongo es no usar los métodos JNIEXPORT de la librería y crear
una aplicación C que recibe por entrada estándar una secuencia de bytes que
indicara que comando ejecutar y con que parámetros y escribirá en la salida
estándar los resultados de la operación que ejecute.
Por la parte
de Java, lo que propongo es no usar los método nativos ni cargar las librerías.
La aplicación Java ejecutará la aplicación C y tomará el control de la
ejecución. Al tomar el control puede:
- Parar la aplicación C y volver a lanzarla.
- Capturar la salida estándar de la aplicación C por lo que puede escribir y leer de ella.
La nueva
arquitectura seria:
La forma en
Java de lanzar una aplicación y tomar el control es la siguiente:
Clase Main:
public class MainNoJNI
{
public static void main (String arg[]) throws Exception{
String process = "D:\\fuentes\\noJNI\\noJNI\\Release\\noJNI.exe";
Runtime rtPrimary = Runtime.getRuntime();
final Process pidPrimary = rtPrimary.exec(process);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
pidPrimary.destroy();
}
}));
DataOutputStream dataOutPrimary = new
DataOutputStream(pidPrimary.getOutputStream());
Date inicio = new Date();
byte [] entrada = generarBytesAltaCliente(new AltaEntrada());
dataOutPrimary.write( entrada );
dataOutPrimary.flush();
dataOutPrimary.close();
DataInputStream dataInPrimary = new
DataInputStream(pidPrimary.getInputStream());
// vamos a suponer que la salida es como mucho de 10 bytes
byte[] salida = new byte[10];
dataInPrimary.read( salida, 0, 10 );
AltaSalida altaSalida = interpretaSalida(salida);
Date fin = new Date();
//System.out.println("Con control has tardado : " + (fin.getTime() - inicio.getTime()) + " milisegundos");
System.out.println( (fin.getTime() - inicio.getTime()) );
pidPrimary.destroy();
}
private static AltaSalida interpretaSalida( byte[] salida )
{
AltaSalida altaSalida = new AltaSalida();
altaSalida.respuesta = salida[0];
byte [] codigo = new byte [4];
codigo[0] = salida[1];
codigo[1]= salida[2];
codigo[2]= salida[3];
codigo[3]= salida[4];
altaSalida.codigoUsuario = new String(codigo);
altaSalida.departamento = salida[5];
altaSalida.esFiable= salida[6];
altaSalida.fechaAltaDia = salida[7];
altaSalida.fechaAltaMes= salida[8];
altaSalida.fechaAltaAnyo = salida[9];
return altaSalida;
}
private static byte[] generarBytesAltaCliente(AltaEntrada altaEntrada)
{
// vamos a suponer que la entrada es como mucho de 10 bytes
byte[] salida = new byte[10];
salida[0] = altaEntrada.tipo; // 1 byte para el tipo de operacion. Alta usuario
byte[] nombre = altaEntrada.nombre.getBytes();
salida[1] = nombre[1];
salida[2] = nombre[2];
salida[3] = nombre[2];
salida[4] = nombre[3]; // 4 bytes para el nombre
salida[5] = altaEntrada.edad; // 1 byte para la edad
salida[6] = altaEntrada.sexo; // 1 byte el sexo
byte[] ret = new byte[2];
ret[0] = (byte)(altaEntrada.codigoPais & 0xff);
ret[1] = (byte)((altaEntrada.codigoPais >> 8) & 0xff);
salida[9] = altaEntrada.codigoCiudad; // 1 bytes para el codigo del ciudad
return salida;
}
}
La clase entrada seria:
public class AltaEntrada
{
public byte tipo;
public String nombre;
public byte edad;
public byte sexo;
public short codigoPais;
public byte codigoCiudad;
public AltaEntrada (){
tipo = 1;
nombre = "pepe";
edad = 20;
sexo = 1;
codigoPais = 300;
codigoCiudad = 100;
}
}
La clase salida:
public class AltaSalida
{
public byte respuesta;
public String codigoUsuario;
public byte departamento;
public byte esFiable;
public byte fechaAltaDia;
public byte fechaAltaMes;
public byte fechaAltaAnyo;
}
El codigo C:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <string>
using namespace std;
string alta (string leido){
string salida;
char nombre[4];
char edad;
char sexo;
unsigned short codigoPais;
char codigoCiudad;
// parseamos
leido.copy(nombre, 4, 1);
edad = leido.at(5);
sexo = leido.at(6);
codigoPais = (leido.at(7)<<8) | leido.at(8);
codigoCiudad = leido.at(9);
// lo que tarde la operacion
Sleep(1000);
// creamos la salida
salida.append(1,0);
salida.append(1,'p');
salida.append(1,'e');
salida.append(1,'p');
salida.append(1,'e');
salida.append(1,12);
salida.append(1,1);
salida.append(1,11);
salida.append(1,10);
salida.append(1,5);
return salida;
}
int _tmain(int argc, _TCHAR* argv[])
{
char comando = -1;
string leido;
string respuesta;
// el comando 0 es cierra la aplicacion
cin >> leido;
comando = leido.at(0);
// es un alta
if (comando == 1)
respuesta = alta (leido);
else
respuesta = -1;
cout << respuesta ;
return 0;
}
Vamos ha
hacer una comparativa con varios conceptos para ver que opción puede resultar
mejor:
|
Concepto
|
JNI
|
Por control
|
|
Memoria
|
Se suma a al tamaño de la aplicación
Java
|
Va a parte de la aplicación Java
|
|
Forma de comunicación
|
Por memoria
|
Por entrada/salida estándar
|
|
Unidad de comunicación
|
Objetos/metodos – mapeo
|
Cadena – parseo
|
|
Error en C
|
Se cierra la aplicación/hilo
|
Se puede detectar y actuar en
consecuencia. La aplicación/hilo continúa
|
|
Instancias
|
Una
|
Infinitas
|
|
Cambio en ejecución
|
No se puede
|
Se puede
|
|
Rendimiento
|
Igual
|
|
Que es cada
concepto:
- Memoria: donde se coloca la parte C en memoria.
- Forma de comunicación: como se comunica la parte Java con la parte C.
- Unidad de comunicación: como Java le dice a C que ejecute un método y como C le da la respuesta de la ejecución.
- Error en C: que sucede en la parte Java si se produce un error grabe en la parte C.
- Instancias: instancias de la parte C que se pueden hacer desde Java.
- Cambio en ejecución: capacidad de cambiar la parte C en ejecución por otra parte C que tenga los mismos métodos.
Teniendo en
cuenta estos conceptos, la arquitectura “por control” parece mejor excepto
quizás en el apartado de Unidad de ejecución ya que JNI trata de que no se note
cuando la ejecución de la aplicación Java pasa por ser C ni que tampoco se note
el fin de esa ejecución C y la ejecución de la aplicación Java vuelve a ser
Java. Desde el punto de la programación, desde Java es mejor pero en la parte C
los objetos no son mapeados directamente si no que están en un objeto
indeterminado y cada campo del objeto hay que buscarlo uno a uno. Si son muchos
el código se complica y no queda tan claro que sea mas “limpio” que pasear un
array de bytes.
¿Pero que
pasa si no usas un objeto y lo que haces es pasarlo parámetro a parámetro?
miércoles, 20 de febrero de 2013
Meditaciones sobre metodologías de desarrollo
Nuestros amigos de JavaHispano han elaborado un documento con algunas meditaciones muy interesantes sobre metodologías de desarrollo.
Os lo recomiendo.
El enlace es http://www.javahispano.org/portada/2013/2/19/niveles-de-calidad-el-agujero-en-las-metodologias-de-softwar.html
Espero que os guste
Os lo recomiendo.
El enlace es http://www.javahispano.org/portada/2013/2/19/niveles-de-calidad-el-agujero-en-las-metodologias-de-softwar.html
Espero que os guste
jueves, 24 de enero de 2013
Como generar un producto a partir de un proyecto
En muchas ocasiones, un proyecto se puede usar para dar
solución a otro proyecto (es mas, es la forma ideal ya que te ahorras la parte de demostrar que la solución tiene salida comercial). Por ejemplo, una pagina web de venta de coches; el
responsable de ventas puede ver la pagina y decir que las funcionalidades son fáciles
de usar y son muy genéricas por lo que podría ser la solución para otro cliente
(es decir, otro proyecto) con algunos cambios claro. Cuando un proyecto es “igual”
que otro pero cambiando “algo” es que el primer proyecto se puede convertir en
un producto y la elaboración del segundo proyecto debe enfocarse como la
transformación del primer proyecto en un producto configurable.
¿Como se puede saber que se ha conseguido elaborar un
producto configurable? Cuando al aplicar una configuración tienes el primer
proyecto y cuando aplicas otra configuración tienes el segundo proyecto.
Ojo, esto es muy importante si el objetivo es obtener un
producto porque como el segundo proyecto digas:
Bueno lo del producto con el tiempo. Ahora cojo el primer
proyecto, lo rehago partiendo de códigos, configuraciones, ficheros, etc… y
termino “RAPIDO” este segundo proyecto..
Es muerte para el producto.
Esto es lo que suele pasar. Merece la pena sacar un producto
bueno que ir “recauchutando” proyectos y llamarlo producto.
Suscribirse a:
Comentarios (Atom)

