Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre open source (publicaciones antiguas, página 13)

¿Cuanto browser entra en 128 líneas de código?

Lo que me gus­ta­ba de ese bro­w­ser de 42 lí­neas era que no era el ejem­plo tí­pi­co, don­de me­ten una vis­ta de We­bkit en una ven­ta­na, car­gan una pá­gi­na y te tra­tan de con­ven­cer de que son unos ba­na­na­s. Esa ver­sión son 7 lí­nea­s:

import sys
from PyQt4 import QtGui,QtCore,QtWebKit
app=QtGui.QApplication(sys.argv)
wb=QtWebKit.QWebView()
wb.setUrl(QtCore.QUrl('http://www.python.org'))
wb.show()
sys.exit(app.exec_())

O 6 si lo so­por­ta­ra un po­co más feo.

¡Pe­ro igua­l, el de 42 se veía úti­l!

This 42-line web browser, courtesy of #python and #qt -- http... on Twitpic

Esos bo­to­nes que se ven fun­cio­na­ban co­rrec­ta­men­te, ha­bi­li­tan­do y des­ha­bi­li­tan­do­se en el mo­men­to co­rrec­to, la en­tra­da de URL cam­bia­ba cuan­do ha­cías cli­ck en un li­nk, y otras co­si­tas así.

Ahí de­ci­dí em­pe­zar un pe­que­ño pro­yec­to in­ter­mi­ten­te de co­de gol­f: me­ter el me­jor bro­w­ser que pue­da en 128 lí­neas de có­di­go (sin con­tar co­men­ta­rios ni blan­co­s), usan­do so­lo Py­Q­t4.

Eso tie­ne un pro­pó­si­to úti­l: siem­pre sos­pe­ché que si uno asu­me Py­Qt co­mo par­te del sis­te­ma ba­se, la ma­yo­ría de las apli­ca­cio­nes en­tra­rían en diske­ttes. Es­ta en­tra unas 500 ve­ces en uno de 1.44MB (¡a­sí que po­dés usar los de 360 de co­m­mo­do­re sin du­pli­disk!)

has­ta aho­ra van 50 lí­nea­s, y tie­ne los si­guien­tes fea­tu­res:

  • Zoom in (C­­tr­­l++)

  • Zoom out (C­­tr­­l+-)

  • Re­set Zoom (C­­tr­­l+=)

  • Bus­­car (C­­tr­­l+­­F)

  • Es­­co­n­­der bús­­que­­da (Es­­c)

  • Bo­­­to­­­nes de atrá­s/a­­de­­lan­­te y re­­ca­r­­gar

  • En­­tra­­da de URL que coi­n­­ci­­de con la pá­­gi­­na + au­­to­­­co­m­­ple­­ta­­do des­­de la his­­to­­­ria + arre­­gla la URL pues­­ta a ma­no (a­­gre­­ga http://, esas co­­sas)

  • Plu­­gins (i­n­­cluí­­do fla­s­h, que hay que ba­­jar apa­r­­te ;-)

  • El tí­­tu­­lo de la ven­­ta­­na mues­­tra el tí­­tu­­lo de la pá­­gi­­na (sin pro­­­pa­­gan­­da del bro­­w­se­­r)

  • Ba­­rra de pro­­­gre­­so pa­­ra la ca­r­­ga de la pá­­gi­­na

  • Ba­­rra de es­­ta­­do que mues­­tra el des­­tino de los li­nks cuan­­do pa­sas el mou­­se

  • To­­­ma una URL en la lí­­nea de co­­­man­­do (o abre http://­­p­­y­­tho­­n.org

  • Mu­l­­ti­­pla­­ta­­fo­r­­ma (fun­­cio­­­na do­n­­de fun­­cio­­­na QtWe­­bKi­­t)

Fal­tan ta­bs y so­por­te de pro­x­y. Es­pe­ro que lle­ven unas 40 lí­neas má­s, pe­ro creo que ya es el más ca­paz de to­dos es­tos bro­w­sers de ejem­plo.

El có­di­go­... no es tan te­rri­ble. Uso mu­chos lamb­da­s, y los ar­gu­men­tos ke­yword de Py­Qt pa­ra co­nec­tar se­ña­le­s, que ha­cen que al­gu­nas lí­neas sean muy lar­ga­s, pe­ro no muy di­fí­ci­le­s. Se po­dría achi­car bas­tan­te to­da­vía!

Aquí es­tá en ac­ció­n:

Y aquí es­tá el có­di­go:

#!/usr/bin/env python
"A web browser that will never exceed 128 lines of code. (not counting blanks)"

import sys
from PyQt4 import QtGui,QtCore,QtWebKit

class MainWindow(QtGui.QMainWindow):
    def __init__(self, url):
        QtGui.QMainWindow.__init__(self)
        self.sb=self.statusBar()

        self.pbar = QtGui.QProgressBar()
        self.pbar.setMaximumWidth(120)
        self.wb=QtWebKit.QWebView(loadProgress = self.pbar.setValue, loadFinished = self.pbar.hide, loadStarted = self.pbar.show, titleChanged = self.setWindowTitle)
        self.setCentralWidget(self.wb)

        self.tb=self.addToolBar("Main Toolbar")
        for a in (QtWebKit.QWebPage.Back, QtWebKit.QWebPage.Forward, QtWebKit.QWebPage.Reload):
            self.tb.addAction(self.wb.pageAction(a))

        self.url = QtGui.QLineEdit(returnPressed = lambda:self.wb.setUrl(QtCore.QUrl.fromUserInput(self.url.text())))
        self.tb.addWidget(self.url)

        self.wb.urlChanged.connect(lambda u: self.url.setText(u.toString()))
        self.wb.urlChanged.connect(lambda: self.url.setCompleter(QtGui.QCompleter(QtCore.QStringList([QtCore.QString(i.url().toString()) for i in self.wb.history().items()]), caseSensitivity = QtCore.Qt.CaseInsensitive)))

        self.wb.statusBarMessage.connect(self.sb.showMessage)
        self.wb.page().linkHovered.connect(lambda l: self.sb.showMessage(l, 3000))

        self.search = QtGui.QLineEdit(returnPressed = lambda: self.wb.findText(self.search.text()))
        self.search.hide()
        self.showSearch = QtGui.QShortcut("Ctrl+F", self, activated = lambda: (self.search.show() , self.search.setFocus()))
        self.hideSearch = QtGui.QShortcut("Esc", self, activated = lambda: (self.search.hide(), self.wb.setFocus()))

        self.quit = QtGui.QShortcut("Ctrl+Q", self, activated = self.close)
        self.zoomIn = QtGui.QShortcut("Ctrl++", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()+.2))
        self.zoomOut = QtGui.QShortcut("Ctrl+-", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()-.2))
        self.zoomOne = QtGui.QShortcut("Ctrl+=", self, activated = lambda: self.wb.setZoomFactor(1))
        self.wb.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)

        self.sb.addPermanentWidget(self.search)
        self.sb.addPermanentWidget(self.pbar)
        self.wb.load(url)


if __name__ == "__main__":
    app=QtGui.QApplication(sys.argv)
    if len(sys.argv) > 1:
        url = QtCore.QUrl.fromUserInput(sys.argv[1])
    else:
        url = QtCore.QUrl('http://www.python.org')
    wb=MainWindow(url)
    wb.show()
    sys.exit(app.exec_())

The Outhouse and the Mall

Wear­ing the soft­ware en­gi­neer's hat: Code is the most triv­ial and the least im­por­tant part of a fea­ture.

—Michael Ia­trou

Michael tweet­ed that, I replied, he replied, but what the heck, I think some­times things can be bet­ter ex­plained in more than 140 char­ac­ter­s, thus this post [1].

So, why the mall and the out­house? Be­cause when we talk about soft­ware and code and fea­tures, we are not all talk­ing about the same thing. Imag­ine if I told you that bricks are triv­ial. Af­ter al­l, they have ex­ist­ed in their cur­rent form for thou­sands of years, they are pret­ty sim­ple to man­u­fac­ture, and have no in­ter­est­ing fea­tures, re­al­ly, ex­cept a cer­tain re­sistence.

Now, sup­pose you are build­ing an out­house. Since you are a fun­ny guy, you want to build an ac­tu­al brick out­house so you will use bricks to do it.

Now, since bricks are so bor­ing, you may feel com­pelled to be­lieve bricks are the least im­por­tant part of your ed­i­fice, and that the over­all de­sign is more im­por­tan­t. Should you carve a moon-shaped hole in the door? How deep should the la­trine be?

How­ev­er, that po­si­tion is fa­tal­ly flawed, since if you ig­nore those triv­ial, bor­ing brick­s, all you have is shit in a hole in the ground. That is be­cause you are con­sid­er­ing the bricks as just a mean to your end. You on­ly care about the bricks in­so­far as they help you re­al­ize your grand out­house vi­sion. I am here to tell you that you are wrong.

The first way in which you are wrong is in that ar­ti­fi­cial sep­a­ra­tion be­tween means and end­s. Ev­ery­one is fa­mil­iar with the eth­i­cal co­nun­drum about whether the ends jus­ti­fy the mean­s, but that's garbage. That'swhat you say when you try to con­vince your­self that do­ing things hap­haz­ard­ly is ok, be­cause what you do is just the means to what­ev­er oth­er thing is the end. Life is not so eas­i­ly di­vid­ed in­to things that mat­ter and things that don't.

Your work, your cre­ation is not just some ide­al iso­lat­ed end to­wards which you trav­el across a sea of dirty mean­s, try­ing to keep your sil­ver ar­mour clean. It's one whole thing. You are cre­at­ing the mean­s, you are cre­at­ing your goal, you are re­spon­si­ble for both, and if you use shod­dy brick­s, your out­house should shame you.

In the same way, if you do crap­py code, your fea­ture is de­meaned. It may even work, but you will know it's built out of crap. You will know you will have to fix and main­tain that crap for years to come, or, if you are luck­y, ru­in your kar­ma by dump­ing it on the head of some poor suck­er who fol­lows your step­s.

I am pret­ty much a ma­te­ri­al­ist. If you re­move the code, you don't have a fea­ture, or soft­ware, you have a con­cep­t, maybe an idea, per­haps a de­sign (or maybe not) but cer­tain­ly not soft­ware, just like you don't have a brick out­house with­out pil­ing some damn bricks one on top of the oth­er.

I al­ways say, when I see some­one call­ing him­self a soft­ware en­gi­neer, that I am mere­ly a soft­ware car­pen­ter. I know my tool­s, I care about them, I use them as well as I can ac­cord­ing to my lights [2] and I try to pro­duce as good a piece of fur­ni­ture as I can with what I am giv­en.

This tends to pro­duce hum­ble soft­ware, but it's soft­ware that has one re­deem­ing fea­ture: it knows what it should do, and does it as well as I can make it. For ex­am­ple, I wrote rst2pdf. It's a pro­gram that takes some sort of tex­t, and pro­duces PDF files. It does that as well as I could man­age. It does noth­ing else. It works well or not, but it is what it is, it has a pur­pose, a de­scrip­tion and a goal, and I have tried to achieve that goal with­out em­bar­ras­ing my­self.

My pro­grams are out­hous­es, made of care­ful­ly se­lect­ed and con­sid­ered brick­s. They are not fan­cy, but they are what they are and you know it just by look­ing at them. And if you ev­er need an out­house, well, an out­house is what you should get.

Al­so, peo­ple tend to do weird stuff with them I nev­er ex­pect­ed, but that's just the luck of the anal­o­gy.

But why did I men­tion malls in the ti­tle? Be­cause malls are not out­hous­es. Malls are not done with a goal by them­selves be­yond mak­ing mon­ey for its builder­s. The ac­tu­al func­tion of a piece of mall is not even known when it's be­ing built. Will this be a Mc­Don­ald­s, or will it be a com­ic book store? Who knows!

A mall is built quick­ly with what­ev­er makes sense mon­ey­wise, and it should look bland and recog­nis­able, to not scare the herd. It's a build­ing made for pedes­tri­an­s, but it's in­tend­ed to con­fuse them and make the path form A to B as long and me­an­der­ing as pos­si­ble. The premis­es on which its de­sign is based are all askew, cor­rupt­ed and self­-­con­tra­dict­ing.

They al­so give builders a chance to make lots of mon­ey. Or to lose lots of mon­ey.

Nowa­days, we live in an age of mall soft­ware. Peo­ple build star­tup­s, get fi­nanc­ing, build crap­py soft­ware and some­times they hit it big (Twit­ter, Face­book) or, more like­ly, fade in­to ob­scu­ri­ty leav­ing be­hind noth­ing at al­l, ex­cept mon­ey lost and sad pro­gram­mers who spent nights cod­ing stuff noone will ev­er see or use, and not much else.

Far from me say­ing star­tups are not a no­ble or wor­thy en­deav­our. They are! It's just that peo­ple who work on them should re­al­ize that they are not build­ing soft­ware. That's why code does­n't look im­por­tant to them, be­cause they are ac­tu­al­ly sell­ing eye­balls to ad­ver­tis­er­s, or col­lect­ed per­son­al da­ta from their users to who­ev­er buys that, or cap­tive pub­lic for game de­vel­op­er­s, or what­ev­er your busi­ness mod­el says (if you have one!).

They are build­ing mall­s, where the val­ue is not in the build­ing, which is pret­ty ghast­ly and use­less by it­self, but on the peo­ple in it, those who rent space in the mal­l, those who will use the mal­l, the soft­ware, the so­cial net­work, what­ev­er it is you are build­ing.

Twit­ter is not soft­ware, Face­book is not soft­ware. If they were, iden­ti.­ca and di­as­po­ra would be big­ger! What they are is peo­ple in one place, like a mall is not a re­al build­ing, but a col­lec­tion of peo­ple un­der a roof.

So, there is noth­ing wrong with build­ing mall­s. Just re­mem­ber that your ends and your means are one and a whole, that code is im­por­tan­t, that with­out code Face­book and Twit­ter don't work, and that with­out peo­ple they are a bad­land, and know what you are do­ing.

Be­cause the on­ly hard thing in life is know­ing what you want to do. The rest is the easy part. And be­cause malls with­out toi­lets suck.

Una nueva etapa, bla bla bla

Bue­no, es­te es uno de eso­s.

Hoy em­pe­cé a tra­ba­jar en Ca­no­ni­ca­l. Sí, en Ca­no­ni­ca­l. Los de Ubun­tu. Tal vez te pre­gun­tes que va a ha­cer un KDEe­ro de la pri­me­ra ho­ra ahí. Bue­no, es un la­bu­ro, los 90s te pi­den que de­vuel­vas el fla­me­fes­t.

Soy el nue­vo "En­gi­nee­ring Ma­na­ger for the Desk­to­p+ grou­p". Qué miérco­les es eso? Bue­no, mi tra­ba­jo es ayu­dar a un gru­po de gen­te que me cae bien (los que co­noz­co al me­no­s) a crear so­ftwa­re co­pa­do.

Pro­ba­ble­men­te no pro­gra­me de­ma­sia­do, ya que es­te es un tra­ba­jo de adul­to, en que lo úni­co que se es­pe­ra que de­sa­rro­lle en per­so­na es una úl­ce­ra gás­tri­ca y la su­per­fi­cie de mi pe­la­da mien­tras arreo ga­tos ha­cia el co­rral mas cer­ca­no, pe­ro pro­ba­ble­men­te me las arre­gle pa­ra ha­cer al­gu­nas co­sas, a ve­ce­s.

Me lle­ga en un buen mo­men­to. Mi pi­be cum­ple 4 el año que vie­ne, y va a es­tar to­do el día en el co­le­gio. Que voy a ha­cer en ca­sa to­do el día? Ver ani­mé? Cons­truir ro­bo­ts ase­si­no­s? Pla­near co­mo con­quis­tar al mun­do, Pi­nk­y?

Y que pa­sa con mi tra­ba­jo an­te­rio­r? Bue­no­... to­da­vía si­gue ahí. Si­go sien­do due­ño de un pe­da­zo de Net Ma­na­gers (http://­ne­t­ma­na­ger­s.­co­m.ar) pe­ro me voy a apar­tar de la ope­ra­ción de la em­pre­sa.

Bá­si­ca­men­te, pien­so que­dar­me con el di­ne­ro y ti­rar­les el tra­ba­jo a mis que­ri­dos so­cios (men­ti­ra). En cual­quier ca­so la em­pre­sa fun­cio­na­rá igua­l, ya que si no sa­co pla­ta po­de­mos con­tra­tar un em­plea­do pa­ra que ha­ga lo que ha­cía yo, así que to­do el mun­do ga­na.

En otras no­ti­cia­s, si­go la­bu­ran­do en la mis­ma me­sa que los úl­ti­mos 5 año­s, ha­cien­do mas o me­nos lo mis­mo, con gen­te dis­tin­ta. Di­cho así no sue­na tan in­te­re­san­te... pe­ro bue­no, hay de­sa­fíos in­te­re­san­tes en es­te nue­vo tra­ba­jo.

Re­su­mien­do: Ca­no­ni­ca­l, po­co de pro­gra­ma­r, si­go sie­no due­ño de ne­t­ma­na­ger­s, es­toy con­ten­to.


Contents © 2000-2023 Roberto Alsina