miércoles, marzo 28, 2007
VLC se pasa a Qt
VLC se pasa a Qt en barrapunto
martes, marzo 20, 2007
Copiar, pegar y código de producción
Hay veces que se juntan varias notas que lees por diversos sitios y te llevan al mismo lugar, al lugar en donde has llegado antes por tus propios medios...
En esta ocasión la moraleja es es Cuidado con el código que cortas/pegas de por ahí. Ya sé, es de lógica, de sentido común pero hay veces que la cosa es bastante sutil. Hay muchos motivos por los que analizarlo, pero entre otros:
- Puede ser código peligroso: Me acabo de encontrar con un ejemplo de código de "ayuda" en un grupo de noticias a través de Reflections on Trusting Example Code en donde se hace la pregunta ¿habrá muchos problemas de seguridad en código posteado por internet?
- Puede ser código simplificado: En exampleCode != productionCode se habla de código copiado directamente del ejemplo de los libros y la diferencia con un código eficiente y mantenible.
- Puede hacer asunciones peligrosas: Hace poco buscando ejemplos de uso de criptografía en .NET, para codificar y decodificar con AES concretamente, casi todos los ejemplos usaban PasswordDeriveBytes que tanto en la MSDN como en la documentación de mono: PasswordDeriveBytes dicen que es obsoleta y que produce problemas de interoperabilidad (no usa un algoritmo estándar) Para el framework 2.0 por cierto existe Rfc2898DeriveBytes.GetBytes que no tiene ese problema, porque, este si, usa un algoritmo estándar, PBKDF2 con HMACSHA1. Lo que asumía el código de ejemplo es que no nos importaba la interoperabilidad ni los estándares, cosa que en este caso por supuesto no es cierta ;)
Copiar, pegar y código de producción en Barrapunto
martes, marzo 13, 2007
POO, el código como diseño, y más cosas
- "Coding Horror: Your Code: OOP or POO?" De porqué la programación orientada a objetos tampoco es la bala de plata, como se comentó también en BP en ¿Ha muerto la orientación a objetos?, que claro, por supuesto que no ha muerto... (y un poco más sobre el mismo tema: Ejecución en el Reino de los Nombres)
- Leo casi con sorpresa que se vuelve a hablar de El código fuente visto como diseño. En The Code is the Design se retoma la tesis del artículo de Jack W. Reeves y lo dice bien claro:
No UML diagram is the essential and final output of the design process, the code is. And when you are coding, you are designing
- En Nuevo scheduler para el kernel Ricardo Galli comenta la propuesta de volver a cambiar el planificador de tareas de linux. Muy interesante
- "Pure Virtual Function Called": An Explanation De la teoría y de la implementación del polimorfismo en C++
- Esta me ha resultado curiosa: CodeShine™ A refactoring tool for Microsoft Visual Basic 6 Desde luego no será por falta de código en VB6 que necesita un repasito...
POO, el código como diseño, y más cosas en Barrapunto
domingo, febrero 11, 2007
Más sobre C++0x, memoria transaccional y paralelismo
- "ISO C++0x: Complete Public Review Draft In October 2007?" de Herb Sutter. Repasa con un montón de enlaces interesantes el nuevo C++. Las propuestas más relevantes: Conceptos, Recolector de basura, Modelo de memoria adaptado a la concurrencia y Librerías para tratar la concurrencia
- Un post acerca de porqué la memoria transaccional puede ser una tendencia equivocada, que ha provocado una larga discusión en "Patrick Logan on Software Transaction Memory" que aún no he procesado
- Un grupo interdisciplinar de investigadores de la universidad de Berkley analiza en The Landscape of Parallel Computing Research: A View from Berkeley como se deberían adaptar algunos conocimientos convencionales con la llegada y popularización de los procesadores multicore. Comentado en Slashdot:" An Overview of Parallelism" y Lambda the Ultimate:"The Landscape of Parallel Computing Research: A View from Berkeley"
"Más sobre C++0x, memoria transaccional y paralelismo" en Barrapunto
jueves, febrero 08, 2007
¿Estructuras de datos sin bloqueos?
En una entrada en su blog, Lock-Free Datastructures, Ulrich Drepper duda de la aplicación actual de estructuras de datos compartidas y sin bloqueos sin implementar un gestor de memoria personalizado. No obstante viene a decir que esto cambiará en un futuro próximo...
Por otro lado otros, menos pragmáticos, aconsejan una vía hacia la iluminación que incluye el paso por esos senderos, advirtiendo, eso si que hay que cambiar de un modo de pensar centrado en el lenguaje a uno centrado en la arquitectura (me pregunto yo si merece la pena perder la preciada portabilidad) Hay a algunos que si les merece la pena: Tom Leonard de Valve
Y por supuesto para quien (como a mi) le apetezca saber más hay por ahí alguna referencia, "Some notes on lock-free and wait-free algorithms" de Ross Bencina y la entrada de la wikipedia inglesa Lock-free and wait-free algorithms
¿Estructuras de datos sin bloqueos? en Barrapunto
lunes, enero 29, 2007
Exceso de información, filtros bayesianos y DIY
Desde que leí esta entrada de manje, "Selección de noticias mediante filtro bayesiano" en la que presentaba su proyecto, lo pensé... ¿por que nadie ha hecho un lector al que lo entrenes y te filtre según lo has entrenado? Bueno, manje lo tiene hecho y se pude probar (es TU PERIODICO)
No estoy seguro de que un filtrado automático sea la solución al exceso de fuentes de información, además de tenerlo que entrenar, con la inversión en esfuerzo que eso supone. Pero a este respecto manje y los usuarios de TU PERIODICO nos pueden comentar más. Yo a nivel personal si que digo que me ha resultado más entretenido programar un miniscrí que entrenar el filtro y que sigo usando bloglines a pesar de haber alternativas seguramente mejores...
En fin, como me interesó la idea, al menos un rato :), pues me puse a hacerlo yo mismo... porqué no, ¿verdad? Total que me hice un script en Ruby, porque me apetecía, porque yo lo valgo y para ser buzzword compliant :) (No sé, a otros les ha servido de algo :)). Como no tengo ningún tiempo de seguir su desarrollo (y tampoco se para que...) lo pongo por aquí por si le sirve a alguien, aunque sea solo de mal ejemplo. Aviso que está hecho con la velocidad y el descuido de la pasión, con lo que no es de calidad de producción ni en la forma ni en la organización.
Permite leer feed por feed en modo interactivo o todo seguido y se va guardando las fechas de última lectura de las fuentes, con lo que en teoría debería mostrar solo los ítems nuevos. En la práctica, sospecho que a mitad por el parser de feeds que he usado, Ruby feedparser, a mitad por que los que los forman no tienen mucho cuidado (pero no lo he analizado en serio) hay fuentes que salen entradas ya leídas. El escrí permite ir llenando su "base de datos" de fuentes o importarlas de bloglines. Permite, claro, entrenarlo (con Classifier, que se instala a través de rubygems) y permite que la salida sea en modo texto, para esos frikis como yo a los que nos encanta la consolica, y claro, para todos aquellos que quieran procesar la salida...
Después de estos preámbulos, ahí va:
require 'rubygems'
require 'stemmer'
require 'classifier'
require 'yaml'
class SimpleFeed
attr_reader :url, :date
attr_writer :date
def initialize(url, date)
@url = url
@date = date
end
end
def serialize( c, name )
File.open( name, 'w' ) do |out|
YAML.dump( c, out )
end
end
require 'net/http'
require 'uri'
def fetch(uri_str, date, limit = 10)
#TODO: I should choose better exception.
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
header={'If-Modified-Since' => date.to_s}
uri=URI.parse(uri_str)
http = Net::HTTP.new(uri.host, uri.port)
response=http.get(uri.path,header)
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else
puts "error getting " + uri_str + response
STDIN.gets()
response.error!
end
end
#const
Filter_file = "filter.yaml"
Feeds_file = "feeds.yaml"
#default options
add_feed = false
train = false
html_content = false
no_interactive = false
bloglines_import = false
bloglines_file = ''
ARGV.each_with_index do |arg,index|
case arg
when '--add_feed'
add_feed = true
when '--train'
train = true
when '--html_content'
html_content = true
when '--no_interactive'
no_interactive = true
when '--bloglines_import'
bloglines_import = true
bloglines_file = ARGV[index+1]
puts bloglines_file
end
end
#load filter
begin
filter =YAML::load_file( Filter_file )
rescue SystemCallError
filter= Classifier::Bayes.new 'Interesting', 'Uninteresting'
end
#load feeds
feeds = Array.new
if(bloglines_import == false)
begin
feeds = YAML::load_file(Feeds_file)
rescue SystemCallError
end
else
require 'rexml/document'
include REXML
file = File.new(bloglines_file)
doc = Document.new(file)
doc.root.each_element('body/outline/outline'){
|outline| feeds.push(SimpleFeed.new(outline.attributes['xmlUrl'],Time.at(0)))
}
end
if(add_feed == true)
print ('Insert a feed, please: ')
f=SimpleFeed.new(STDIN.gets().chop!,Time.at(0))
feeds.push(f)
end
require 'feedparser'
require 'feedparser/html2text-parser'
#iterate the feeds
feeds.each{ |sf|
puts 'Loading '+sf.url + ' ...'
begin
res=fetch(sf.url,sf.date)
s= res.body
rescue
puts "Error getting "+ sf.url
end
begin
#puts res['Date']
mod_date = res['Last-Modified']
puts mod_date
#URI::parse(sf.url), header
rescue
puts res
puts "Error: Web server doesn't implement date: "+ sf.url
end
begin
f = FeedParser::Feed::new(s)
if( f != nil and f.title!=nil )
puts(f.title)
else
puts("Title not available")
end
rescue
puts "Error parsing feed, Not valid: " + sf.url + "\n" +s
end
#Feeds are usually in temporal reverse order
if(f!=nil and f.items!=nil)
f.items.reverse_each {
|i|
#title, date, content
begin
if((i.date ==nil or sf.date==nil or i.date>sf.date) )
if(html_content == false and i.content != nil)
p = FeedParser::HTML2TextParser::new(true)
p.feed(i.content)
p.close
i.content = p.savedata
end
#TODO: -> content NULL
entry = ''
if i.title
entry+=i.title + " "# + i.date.to_s
end
if(i.content != nil)
entry+=i.content
end
puts(entry)
#puts ("Most recent date: " +sf.url+ " "+ i.date.to_s)
if(i.date!=nil)
sf.date=i.date
else
if (mod_date !=nil)
#If mod_date exists
sf.date=mod_date
end
end
if(train)
print(' (Interesting[Y/n]?)')
ans=STDIN.gets().chop!
print(ans)
if ans=='n'
filter.train_uninteresting(entry)
else
filter.train_interesting(entry)
end
else
puts(filter.classify(entry))# returns '[Un]interesting'
if(no_interactive==false)
STDIN.gets()
end
end
end
rescue
puts "Unknown Error"
end
}
end
}
serialize(filter, Filter_file)
serialize(feeds, Feeds_file)
La misma entrada en BP
lunes, diciembre 18, 2006
Memoria transaccional y concurrencia
En ACM Queue han publicado un articulo que ilustra bastante bien por donde irán los tiros (seguramente) en esto de la programación concurrente. Se trata de Unlocking Concurrency: Multicore programming with transactional memory y describe un poco que es la memoria transaccional y como se programaría en un lenguaje de los de uso cotidiano.
Básicamente se trata de especificar en el lenguaje que secuencias de operaciones forman una transacción de memoria, en la cual, como su nombre indica, o bien se realiza la operación completamente o bien es como si no se hubiese operado con ella, evitando la sincronización manual por parte del programador. Como se encargan de subrayar en el artículo tampoco es la panacea, pero ayuda(ría) mucho a la gestión de la concurrencia.
Sólo falta ahora que se implemente en lenguajes de uso común y deje de ser sólo objeto de investigación académica...
La misma entrada en BP
jueves, diciembre 14, 2006
Una herramienta, no una religión
En resumen, en lugar de criticar herramientas, aprende su ámbito de aplicación...Recientemente he estado asistiendo al debate de REST contra SOA. La última semana me vi envuelto en discusiones de C++ contra Java. Esta noche pasada me tropecé con algunos debates sobre Django contra Rails. Me parece que los ingenieros de software somos únicos en el mundo técnico: más que disfrutar con una caja de herramientas variada, discutimos contra su contenido, esperando descartar todas excepto el conjunto más pequeño posible.
[...]
¿Porque debemos trabajar tanto en reducir nuestro conjunto de herramientas hasta la herramienta definitiva? Hay una tendencia a buscar el lenguaje Navaja suiza apoyado por un framework que será la solución óptima para todos los problemas del mundo. La simple realidad es que ese lenguaje o framework no existe. ¿Por qué? Bueno, la solución de problemas informáticos es siempre acerca de adoptar compromisos que optimicen la solución en determinadas condiciones. Si tu problema cumple esas condiciones, perfecto. Si no, estarás usando una herramienta subóptima.
[...]
Es importante tener opciones para resolver los problemas de cada día. Entender las herramientas y su aplicabilidad a un problema dado debería ser nuestro trabajo
La misma entrada en BP
domingo, diciembre 03, 2006
sky2 y sk98lin en Ubuntu
Referencias:
sk98lin en la wiki de gentoo en la que se explica un poco la historia
Una explicación de la situación el la lista del kernel
Entrada original:
Tenía problemas con el driver de la tarjeta de red, una Marvell Yukon, desde la actualización a Dapper y no lo sabía, porque no la usaba últimamente. Si se hace un uso intensivo de la red (léase P2P ;) ) sky2, que es el driver que ubuntu coge por defecto, se quedaba atascado. El caso es que he buscado (quizás no mucho) y no he encontrado, como suele ser usual, la receta sencilla. Lo que me ha servido a mi es:
- Instalar las cabeceras del kernel (en mi caso y salvo casos excepcionales linux-headers-generic)
- sudo apt-get install build-essential (si no lo tenemos)
- Bajar el driver de http://www.marvell.com/drivers/driverSearchResults.do y descomprimirlo
- Sustiuir #!/bin/sh por #!/bin/bash en el fichero install.sh
- En el directorio descomprimido: sudo ./install.sh y damos a 1. Installation
- sudo modprobe sk98lin
- añadir la línea blacklist sky2 al final del fichero /etc/modprobe.d/blacklist (edítalo como root o con sudo)
(Basada en dos recetas, para mi, incompletas: http://www.ubuntu-es.org/index.php?q=node/30706 y http://ubuntuforums.org/showthread.php?t=176096 )
La misma entrada en BP
jueves, noviembre 30, 2006
Programadores e interfaces de usuario
- El programador tiende a ver la funcionalidad, no el uso.
- El programador no tiene la formación adecuada (ni el interés(?)) acerca de usabilidad ni diseño. Quizás tampoco la formación adecuada en programación de GUI's
- El programador, casi por definición es vago. Gastará el mínimo tiempo en el diseño del interfaz
También hay algunos aspectos que dificultan que un interfaz sea armonioso y usable: los continuos cambios de especificaciones, la indefinición de funcionalidad y de diseño:
- Eso... uhmmm... déjalo también configurableDe todos modos lo que a mi me parece adecuado es que el programador programe un interfaz de usuario diseñado por un diseñador conjuntamente con el cliente, o al menos validado por éste. Si no hay más remedio que diseñarlo por lo menos intentar no hacer el diálogo. En ese mismo enlace hay consejos sencillos sobre lo que no hay que hacer. El ejemplo del GUI de wget es espeluznante... :)
- Ya, ¿pero dónde?
- Ya le encontrarás un hueco...
- Con tantas opciones ¿no será un poco difícil de usar?
- ...
La misma entrada en BP
