Li um artigo bacana do Tom DeMarco (bastante conhecido pelo livro Peopleware, que é bem interessante por sinal) sobre a mudança de visão dele do gerenciamento de projetos de software.
A visão dele é consistente com o que vem se falando ultimamente, que ao invés de fazer analogias com a construção civíl, desenvolvimento de software é mais parecido com "escrever", ou outras formas de produção artística. Não existe um jeito muito prático de mensurar como um autor de livro está desempenhando seu papel. (Pelo menos não antes do livro ser lançado, hehe)
Achei bacana a atitude do Tom DeMarco de reconhecer que o trabalho dele já não é mais válido, e com certeza é uma prova de que metodologias ágeis tem algum mérito.
domingo, 30 de agosto de 2009
Software Engineering: An Idea Whose Time Has Come and Gone?
Postado por Renato Besen às 20:37 0 comentários Links para esta postagem
domingo, 16 de agosto de 2009
Guia do Mochileiro das Galáxias
Sem nenhum motivo especial, vou colocar aqui os meus quotes preferidos do primeiro livro dessa fantástica trilogia de quatro (+1) livros.
Enquanto isso, o pobre peixe-babel, por derrubar os obstáculos à comunicação entre os povos e culturas, foi o maior responsável por guerras sangrentas, em toda a história da criação.
Quando um [não mochileiro] descobre que um mochileiro tem uma toalha, ele automaticamente conclui que ele tem também escova de dentes, esponja, sabonete, lata de biscoitos, garrafinha de aguardente, bússola, mapa, barbante repelente, capa de chuva, traje espacial, etc, etc.
(…) a geografia de Damogran não é nada prática. Consiste apenas em algumas ilhas desertas de tamanho médio e grande, separadas por oceanos de rara beleza, mas de uma vastidão chatíssima.
Prostetnic Vogon Jeltz sorria muito devagar – não que ele quisesse fazer gênero, estava tentando lembrar-se da sequência de contrações musculares necessárias para realizar o ato.
Trillian desconfiava que ele [Zaphod] conseguia levar uma vida tão louca e bem-sucedida principalmente por não entender jamais o verdadeiro significado de nada que ele fazia.
Fazia tudo com uma mistura de extraordinária genialidade e incompetência ingênua, sendo muitas vezes difícil saber distinguir uma coisa da outra.
Ah, a vida – disse Marvin, lúgebre. - Pode-se odiá-la ou ignorá-la, mas é impossível gostar dela.
Postado por Renato Besen às 16:06 1 comentários Links para esta postagem
sexta-feira, 26 de junho de 2009
Executors/FutureTask Vs. Oberver
Antes de começar, este post é específico pra Java. Se não se interessar por java, pule pro próximo post, ou não.
Pra quem não conhece, o padrão observer serve basicamente pra monitorar mudanças de estado em um objeto. Como todo padrão de projeto, o observer pode ser subvertido para fazer coisas onde existem opções melhores.
Exemplo: é preciso mostrar um diálogo com "OK" e "Cancel" para o usuário, e uma ação externa deve ser executada, dependendo da resposta do usuário.
Uma primeira idéia é cadastrar um listener no diálogo, e dependendo do botão clicado, um método do listener é notificado. Um exemplo de listener seria:
/**
* Interface de um Listener.
*/
public interface Listener {
/**
* Método notificado ao cancelar o diálogo.
*/
void onFailure();
/**
* Método notificado ao aceitar o diálogo.
*/
void onSuccess();
}
Uma possivel implementação de diálog usando esse listener:
/**
* Implementação de um diálogo onde a resposta da ação do usuário é capturada
* através de um listener.
*/
class ListenerFrame {
/** Frame principal. */
private final JFrame frame;
/** Ação do botão de ok. */
private final ActionListener okAction = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
listener.onSuccess();
}
};
/** Ação do botão de cancelar. */
private final ActionListener cancelAction = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
listener.onFailure();
}
};
/** Instância do listener que deve ser noticada. */
private final Listener listener;
/**
* Constroi uma instância de ListenerFrame.
*
* @param l
* o listener a ser notificado.
*/
public ListenerFrame(final Listener l) {
listener = l;
frame = new JFrame();
final JButton ok = new JButton("OK");
ok.addActionListener(okAction);
final JButton cancel = new JButton("Cancel");
cancel.addActionListener(cancelAction);
final JPanel panel = new JPanel();
panel.add(ok);
panel.add(cancel);
frame.add(panel);
frame.pack();
}
/**
* Exibe o frame.
*/
public void show() {
frame.setVisible(true);
}
}
Como podem ver, no botão ok "onSuccess()" é chamado, e em cancelar "onFailure()" é chamado.
Uma classe usando esse diálogo, a título de exemplo:
/**
* Exemplo de utilização de um frame onde a resposta é dada por um listener.
*/
public class ListenerFrameExample {
/**
* O programa cria um novo ListenerFrame passando um listener como
* argumento.
*
* @param args
*/
public static void main(final String[] args) {
new ListenerFrame(new Listener() {
@Override
public void onSuccess() {
System.out.println("YAY!");
System.exit(0);
}
@Override
public void onFailure() {
System.out.println("OH NOES!");
System.exit(0);
}
}).show();
}
}
O problema aqui é que eu estou usando o padrão observer pra esperar uma resposta, e não uma mudança de estado. Se eu puder continuar com a execução do programa, isso até não tem tanto problema, mas a intenção aqui claramente não é essa. E como intensão em um código é (quase) tudo, deve haver um jeito melhor de fazer isso ;)
É ai que entra a FutureTask. Como podem na documentação, a FutureTask serve pra guardar um resultado que vai ser requisitado no futuro, e é exatamente isso que queremos: saber o futuro resultado da ação do usuário.
Primeiro, podemos esquecer a classe Listener. Toda a parde de resposta vai ser encapsulada no diálogo.
/**
* Implementação de um diálogo onde a resposta da ação do usuário é capturada
* por uma FutureTask.
*
*/
class ExecutorFrame {
/** Frame principal. */
private final JFrame frame;
/** Variável auxiliar utilizada para capturar a resposta do usuário. */
private Boolean success;
/** FutureTask criada para encapsular a resposta do usuário. */
private final FutureTask hadSuccess = new FutureTask(
new Callable() {
public Boolean call() throws Exception {
return success;
};
});
/** Ação do botão de ok. */
ActionListener okAction = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
success = true;
// FutureTask é executada, liberando hadSuccess()
Executors.newSingleThreadExecutor().execute(hadSuccess);
}
};
/** Ação do botão de cancelar. */
ActionListener cancelAction = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
success = false;
// FutureTask é executada, liberando hadSuccess()
Executors.newSingleThreadExecutor().execute(hadSuccess);
}
};
/**
* Constroi uma instância de ExecutorFrame.
*/
public ExecutorFrame() {
frame = new JFrame();
final JButton ok = new JButton("OK");
ok.addActionListener(okAction);
final JButton cancel = new JButton("Cancel");
cancel.addActionListener(cancelAction);
final JPanel panel = new JPanel();
panel.add(ok);
panel.add(cancel);
frame.add(panel);
frame.pack();
}
/**
* Exibe o frame.
*/
public void show() {
frame.setVisible(true);
}
/**
* Retorna a resposta do usuário. O método fica travado até que o usuário
* clique em um botão.
*
* @return {@code true} caso o usuario clique em OK, {@code false} caso
* clique em cancelar.
*/
public boolean hadSuccess() {
try {
return hadSuccess.get();
} catch (final InterruptedException e) {
} catch (final ExecutionException e) {
}
return false;
}
}
O método "get()" da FutureTask trava a execução até a tarefa seja executada. Uma FutureTask é criada para guardar o resultado, e as ações dos botões simplesmente executam a tarefa, fazendo assim com que "hadSuccess()" retorne o resultado correto.
A utlização desse dialogo fica assim:
/**
* Exemplo de utilização de um frame onde a resposta é dada por uma FutureTask.
*/
public class ExecutorFrameExample {
/**
* O programa instancia um frame e aguarda a sua resposta. Note que
* d.hadSuccess() fica travado até o usuário clicar em um botão.
*
* @param args
*/
public static void main(final String[] args) {
final ExecutorFrame d = new ExecutorFrame();
d.show();
if (d.hadSuccess()) {
System.out.println("YAY!");
} else {
System.out.println("OH NOES!");
}
System.exit(0);
}
}
Eu particularmente acho bem mais interessante desse jeito. Obviamente cada implementação tem suas vantagens e desvantagens, mas a intenção da segunda opção está bem mais clara do que a primeira.
Outras leituras:
http://en.wikipedia.org/wiki/Swing_%28Java%29
http://en.wikipedia.org/wiki/Observer_pattern
http://sourcemaking.com/design_patterns
Postado por Renato Besen às 00:15 1 comentários Links para esta postagem
Marcadores: code, design.patterns, java, observer, threads
terça-feira, 14 de abril de 2009
Python: PyQt Model/View
Imagino que todos conheçam o padrão de projeto MVC, o famoso Model/View/Controller. A idéia é separar a visualização (interface com o usuário) do controle (os "comandos" que o usuário executa) e do modelo (os dados e a lógica de negócio).
Uma pequena variação disso é o model/view, quando não é necessário controle, ou o controle está em um outro lugar. O MVC completo é um padrão arquitetural, sendo que o "MV" é um padrão mais localizado. Acredito que isso fique mais claro ao final do post :-).
A partir do Qt 4, alguns widgets passaram a suportar o padrão MV. Os antigos QListWidget, QTableWidget, etc. foram substituídos pelo QListView, QTableView, etc. As classes de modelo foram adicionadas para completar o padrão, e para conectar ambos basta um simples someView.setModel(someModel).
Um exemplo usando algumas classes padrão:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
app = QApplication([])
view = QListView()
model = QStringListModel("item1 item2 item3 item4 item5".split())
view.setModel(model)
view.show()
sys.exit(app.exec_())
Qualquer mudança no model é refletida automaticamente na view, e é isso que torna o padrão interessante. É possível ter várias views para um model, e também existe o conceito dos delegates, que servem para dar flexibilidade à entrada de dados. Para não me alongar muito, não vou entrar nos detalhes, mas isso tudo pode ser visto com mais profundidade em Qt Model/View Programming.
model.setData(model.index(0), QVariant("aaaa"))
Agora um exemplo de classe que implementa um modelo abstrato. Supondo que eu queira um modelo de uma série de resultados numéricos, como proceder?
O primeiro passo é criar uma classe que implemente uma QAbstractTableModel:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class ResultTableModel(QAbstractTableModel):
def __init__(self, parent = None):
super(QAbstractTableModel, self).__init__(parent)
self.results = []
Como pode ser visto aqui, o meu modelo deve sobrescrever alguns métodos para que ele possa utilizado. Caso o modelo necessite apenas ser lido (read-only), os métodos flags(), data(), headerData() e rowCount() devem ser providos. Este quatro métodos são suficientes para um QAbstractListModel, mas como estou implementando uma tabela, columnCount() também deve ser provido.Uma implementação básica seria:
def rowCount(self, parent = QModelIndex()):
return len(self.results)
def columnCount(self, parent = QModelIndex()):
return 1 # por enquanto não quero mais de uma coluna
def flags(self, index):
# quero todos os itens habilitados e editáveis
return Qt.ItemIsEnabled | Qt.ItemIsEditable
# Recupera um dado de um índice (QModelIndex)
def data(self, index, role):
# índice não é válido, então retorno um dado vazio
if not index.isValid():
return QVariant()
# se a linha está fora dos bounds da minha lista, resultado vazio
if index.row() >= len(self.results):
return QVariant()
# se o role é o DisplayRole (ou seja, o valor que deve ser renderizado)
# retorno o valor que esta na linha lista
if role == Qt.DisplayRole:
return QVariant(self.results[index.row()])
else:
# podemos retornar valores específicos para outros roles,
# por exemplo ToolTipRole. Pela simplicidade, ignoramos isso.
return QVariant()
# Recupera os cabeçalhos da tabela
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return QVariant()
if orientation == Qt.Horizontal:
# Results vai aparecer no topo da linha
return QVariant("Results")
else:
# em cada linha, mostrar o numero dela no início
return QVariant("%s it." % (section + 1,))
Pronto, agora já podemos exibir o modelo em uma QTableView :-).
No próximo post irei mostrar como fazer para um model ser editável e redimensionável.
Outros materiais:
MVC
Model/View Programming
Model Subclassing
QTableView
QAbstractTableModel
Qt Documentation
Postado por Renato Besen às 23:51 3 comentários Links para esta postagem
quinta-feira, 26 de março de 2009
Python: (des)empacotando argumentos
Packing/unpacking de argumentos é algo que as vezes é esquecido em Pytho e é bem útil em algumas situações.
Packing permite uma função receber um número arbitrário de argumentos:
In [1]: def a(*b): ...: print len(b), b ...: ...: In [2]: a(1,2,3,4,5) 5 (1, 2, 3, 4, 5)
O unpacking faz o serviço contrário, ou seja, ao chamar uma função, os argumentos de uma tupla podem ser "explodidos" (na falta de uma palavra melhor). Aqui vai um exemplo bem prático disso, usando o QColor do PyQt:
color = (255, 0, 0) QColor.fromRgb(*color) # ao invés de QColor.fromRgb(color[0], color[1], color[2])
A função recebe 3 argumentos (r, g, b), e usando o unpacking economizamos alguns caracteres.
Tem mais algumas dicas na documentação oficial, incluindo a possibilidade de usar isso pra keyword arguments usando a notação "**".
Postado por Renato Besen às 21:10 0 comentários Links para esta postagem
quinta-feira, 19 de março de 2009
domingo, 1 de março de 2009
ZFS
O FLOSS Weekly entrevistou nessa semana Aaron Newcomb e David Brittle, falando sobre o ZFS. Pra quem não sabe, ZFS é um sistema de arquivos que vem sendo desenvolvido pela Sun há um tempo, com características bem interessantes.
A entrevista tem cerca de 75 minutos, e pode ser encontrada aqui.
Postado por Renato Besen às 10:36 1 comentários Links para esta postagem
Marcadores: dicas, open-source, podcasts, zfs
quinta-feira, 15 de janeiro de 2009
O Arqueiro
Comecei a ler O Arqueiro, de Bernard Cornwell. Vou colocar dois quotes do livro aqui, pra passar minha impressão do livro.
- Filho da puta idiota - disse Jake. - Eu não ia machucá-lo. Não muito.
- Eu vou me embebedar, padre - disse Thomas, feliz. - Vou ficar tão bêbado que uma daquelas duas garotas vai parecer atraente. - Ele fez um gesto com a cabeça em direção às filhas da viúva.Ou seja, excelente!
O padre Hobbe inspecionou-as com ar crítico, e depois suspirou.
- Você vai se matar bebendo tanto assim, Thomas.
Postado por Renato Besen às 10:51 0 comentários Links para esta postagem
Marcadores: livros
sábado, 20 de dezembro de 2008
Livros
Com o ano quase acabando, começam as retrospectivas e previsões. A minha retrospectiva aqui vai ser de alguns livros que li esse ano. Vou dividir os livros em duas categorias. Neste primeiro post vou colocar alguns livros NÃO relacionados à computação, e no próximo post vou colocar alguns livros técnicos que achei interessante. Se alguém tiver algumas indicações de leitura pro próximo ano, por favor deixem um comentário :-).
Lembrando que a lista não está em nenhuma ordem específica.
- Historias de Robôs Vol. 3 (Isaac Asimov) - Diversos contos de ficção científica, escritos por vários autores e editado pelo fantástico Isaac Asimov. O interessante é ver a visão do futuro que se tinha no passado, e como algumas coisas que hoje são normais foram vislumbradas pelas mentes criativas dos autores. O livro é ideal pra quem gosta de ler em qualquer lugar (no ônibus, fila de banco, etc.), pois os contos não são muito grandes, o que não demanda muita concentração.
- Blink (Malcolm Gladwell) - Esse livro, na minha opinião, foi um pouco overhyped. Escutei falar bastante dele, e acabei comprando. Ele fala sobre a tomada rápida de decisões, e como as vezes perder muito tempo pensando e analisando um problema pode prejudicar um julgamento. Eu me decepcionei um pouco com o livro, mas apesar disso é interessante.
- Freakonomics ( Steven D. Levitt, Stephen J. Dubner) - Esse livro também teve muito hype, mas ao contrário do Blink, eu gostei bastante. A idéia é pegar vários temas, e fazer uma análise de causas e consequências. Um exemplo é a relação entre liberação do aborto nos "US and A" e a diminuição da criminalidade na década de 90. Vários temas polêmicos são abordados, e eu achei bem interessante, principalmente pra pessoas mais curiosas do que o normal.
- O dia do Chacal (Frederick Forsyth) - O dia do Chacal conta a história de uma tentativa de assassinato contra o presidente francês Charles de Gaulle. O protagonista é o Chacal (d'oh), e a história vai desde a contratação do rapaz até o... na, não vou colocar spoilers aqui :-). Este livro foi adaptado para um filme homônimo em 1973, e em 1997 um outro filme foi baseado no livro, desta vez chamado de "O Chacal", com uma história adaptada para padrões estado-unidenses.
- 3001: A Odisséia Final (Arthur Clark) - Pra quem não sabe, Arthur C. Clark é um dos mais fodásticos autores de ficção científica, um dos pais do gênero tão apreciado pelos nerds. 3001 é o livro final da série "Odisséia no Espaço", e conta como o ex-astronauta Frank Poole, que foi morto pelo HAL-9000 em "2001", foi encontrado flutuando no espaço, e foi revivido com uma técnica médica criada na época. O legal desse livro é que o futuro previsto não tem nada de muito absurdo, são coisas que se pensarmos bem são realmente possíveis (pelo menos em partes).
- The Fountainhead (Ayn Rand) - Fugindo um pouco do sci-fi, e partindo pra filosofia, entra "The Fountainhead", ou "A Nascente" em brasileiro. O livro conta a história de Howard Roark, um arquiteto modernoso e incorruptível, e segundo a Ayn Rand, um homem como deveria ser. O livro é um clássico, está sempre nas listas de livros que todo mundo deve ler, e eu fiz a minha parte :D. O plot se baseia na figura do Roark, e nos relacionamentos dele com os outros personagens. O livro é muito envolvente, principalmente pelas atitudes que são tomadas no decorrer da história. As atitudes, pelo menos pra mim, são normalmente angustiantes (mas plausíveis (ou não) no mundo real) e é essa angústia que faz com que você não queira parar de ler, até saber o que acontece depois. A idéia do título é que "o ego é a nascente do progresso humano".
- Silmarillion (J. R. R. Tolkien) - A bíblia de Tolkien. Pra quem curte as histórias de Tolkien, esse livro conta toda a criação do universo que ele imaginou, e vários eventos que precedem as histórias mais famosas dele. O livro é na verdade uma coleção de histórias, e o plot é centrado nas Silmarilli, as jóias criadas por Fëanor, que aprisionam a luz das duas árvores que ficavam no "paraíso" (Valinor). As tais jóias foram roubadas pelo Melkor / Morgoth, e a partir dai começa a desgraça toda. A comparação com a bíblia vem principalmente pelo tipo de narrativa, com um detalhamento absurdo das árvores genealógicas, e pouquíssimos detalhes. Eu li a versão em inglês, e me arrependi um pouco. A linguagem é bem rebuscada e de difícil compreensão, principalmente nas falas dos Valar. Pra quem quer se aprofundar no universo de Tolkien, é imperdível.
- The Hobbit (J. R. R. Tolkien) - O hobbit conta a história de Bilbo Baggins, e a aventura pra recuperar o tesouro que uns anões malucos perderam pro Smaug. A história é bem fast paced, e conta desde a vida caseira do hobbit, a transformação dele em um aventureiro, o achado de um anel do poder, e vai além da recuperação do tesouro. Os personagens são bem carismáticos, e a história também mostra como o Gandalf é um porra-louca completo, que fica desaparecendo nas horas mais importantes :D. Lembrando também que está sendo produzido um filme sobre o Hobbit, e se não me engano vão ser 2 filmes pra cobrir a história inteira.
Postado por Renato Besen às 14:39 0 comentários Links para esta postagem
Marcadores: 2008, dicas, livros, retrospectiva
segunda-feira, 3 de novembro de 2008
Ordenar linhas no vim
Uma dica rápida pros machos (de todos os sexos) que usam vim:
Suponha que você tem um arquivo C / Python / Java / Whatever, e esse arquivo tem alguns includes / imports / whatevers no topo. No calor do momento (porque programar pode ser emocionante), ninguém se importa (sacou?) muito com a ordem das coisas. Claro que na hora do refactoring, é bom deixar a bagaça ordenadinha, porque é muito mais tranquilo de se achar assim. Como fazer isso do jeito fácil? Ai vão os passos no vim:
- Selecione as linhas pra ordenar apertando "V" para ir no modo visual, e com as setas direcionais escolha as linhas onde estão os includes (quem usa gVim pode usar o mouse aqui... n00bs!)
- Digite ":!sort" (sem aspas... mas acho que você já sabia disso :-)
- Sorria!
E depois dizem que vi / vim é complicado...
Postado por Renato Besen às 13:51 3 comentários Links para esta postagem



