Skip to main content

Ralsina.Me — Roberto Alsina's website

Posts about open source (old posts, page 13)

How much web browser can you put in 128 lines of code?

UP­DATE: If you read this and all you can say is "o­h, he's just em­bed­ding We­bKit", I have two things to tell you:

  1. Duh! Of course the 128 lines don't in­­­clude the ren­der­ing en­gine, or the TCP im­­ple­­men­­ta­­tion, or the GUI tool­k­it. This is about the rest of the browser, the part around the web ren­der­ing en­gine. You know, just like Aro­ra, Rekon­q, Epiphany, and ev­ery­one else that em­beds we­bkit or mozil­la does it? If you did­n't get that be­­fore this ex­­pla­­na­­tion... facepalm.

  2. Get your favourite we­bkit fork and try to do this much with the same amount of code. I dare you! I dou­ble dog dare you!

Now back to the orig­i­nal ar­ti­cle


To­day, be­cause of a IRC chat, I tried to find a 42-­line web brows­er I had writ­ten a while ago. Sad­ly, the paste­bin where I post­ed it was dead, so I learned a lesson: It's not a good idea to trust a paste­bin as code repos­i­to­ry

What I liked about that 42-­line brows­er was that it was not the typ­i­cal ex­am­ple, where some­one dumps a We­bkit view in a win­dow, loads a page and tries to con­vince you he's cool. That one is on­ly 7 lines of code:

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_())

And if I want­ed to make the code uglier, it could be done in 6.

But any­way, that 42-­line brows­er ac­tu­al­ly looked use­ful!

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

Those but­tons you see ac­tu­al­ly worked cor­rect­ly, en­abling and dis­abling at the right mo­men­t, the URL en­try changed when you clicked on links, and some oth­er bit­s.

So, I have de­cid­ed to start a smal­l, in­ter­mit­tent project of code golf: put as much brows­er as I can in 128 lines of code (not count­ing com­ments or blanks), start­ing with PyQt4.

This has a use­ful pur­pose: I al­ways sus­pect­ed that if you as­sumed PyQt was part of the base sys­tem, most apps would fit in flop­pies again. This one fits on a 1.44MB flop­py some 500 times (so you could use 360KB com­modore flop­pies if you prefer­!).

So far, I am at about 50 lines, and it has the fol­low­ing fea­tures:

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

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

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

  • Find (C­tr­l+F)

  • Hide find (Esc)

  • But­­tons for back­­/­­for­ward and reload

  • URL en­try that match­es the page + au­­to­­com­­plete from his­­to­ry + smart en­try (adds http://, that kind of thing)

  • Plug­ins sup­­port (in­­clud­ing flash)

  • The win­­dow ti­­tle shows the page ti­­tle (with­­out brows­er ad­ver­tis­ing ;-)

  • Progress bar for page load­­ing

  • Sta­­tus­bar that shows hov­­ered links URL

  • Takes a URL on the com­­mand line, or opens http://python.org

  • Mul­ti­­plat­­form (works in any place QtWe­bKit work­s)

Miss­ing are tabs and proxy sup­port. I ex­pect those will take an­oth­er 40 lines or so, but I think it's prob­a­bly the most fea­ture­ful of these toy browser­s.

The code... it's not all that hard. I am us­ing lamb­da a lot, and I am us­ing PyQt's key­word ar­gu­ments for sig­nal con­nec­tion which makes lines long, but not hard. It could be made much small­er!

Here it is in ac­tion:

And here's the code:

#!/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.

A new stage, blah blah blah

You sure­ly have seen a mil­lion posts like this one. Hack­er X starts say­ing what a great time he had at com­pa­ny Y/­col­lege/­mom's base­men­t/the cir­cus and how he will al­ways miss the peo­ple there but any­way it's great to look for­ward to the chal­lenge of life at com­pa­ny Z/unem­ploy­men­t/feng shui con­sult­ing/ele­fant ex­cre­ment shov­el­ing.

Well, this one is pret­ty much the same thing.

I start­ed work­ing at Canon­i­cal to­day. Yes, Canon­i­cal. The Ubun­tu guys. You may won­der what a dyed-in-the-­wool KDE guy is go­ing to do there. Well, it's a job, dude, the 90s called and they want their flame­fest back.

I am the new "Engi­neer­ing Man­ag­er for the Desk­top+ group". What the heck is that? Well, my job is to help a bunch of tal­ent­ed peo­ple I like (at least the ones I've known so far ;-) de­liv­er cool soft­ware.

I will prob­a­bly not be cod­ing much, since this is a grownup job, the kind where in­stead of lines of code you are sup­posed to de­vel­op gas­tric ul­cers and re­ced­ing hair­lines while you herd cats to the clos­est cat shed, but I will prob­a­bly man­age to do some­thing, some­times.

This po­si­tion came at a good time for me. My kid is go­ing to be 4 next year and go to school all day. What the heck was I gonna do at home all day then, watch ani­me? Build killer robot­s? Plan how to con­quer the world?

And what hap­pens to my pre­vi­ous job? Well... I still have it some­how. I own a piece of Net Man­agers (http://net­man­ager­s.­com.ar) but I will be step­ping away from the dai­ly man­age­ment and op­er­a­tion of the busi­ness.

So, ba­si­cal­ly, I in­tend to take the mon­ey and dump the work on the backs of my ca­pa­ble part­ners (just kid­ding). In any case, the com­pa­ny can work just as well with­out me since we can now maybe hire an em­ploy­ee in­stead of pay­ing me, so it's win/win ;-)

On oth­er news, I will still work in the same ta­ble as the last 5 years, do­ing some of the same things, with dif­fer­ent peo­ple. It does­n't sound so big when said like that, uh? Well, I will trav­el more, and there are in­ter­est­ing chal­lenges in this new job.

In short: canon­i­cal, lit­tle cod­ing, still own net­man­ager­s, hap­py guy.


Contents © 2000-2023 Roberto Alsina