Pages: << 1 ... 16 17 18 19 20 21 22 23 24 25 26 >>


Permalink 10:41:36 pm, by fumanchu Email , 554 words   English (US)
Categories: IT

The true role of a software architect

This past Friday I received a new feature request for our core business application. There's a report which nearly everyone on staff uses; it shows Mission Trips for a given set of dates. Most often, our staff will simply show all current and future Trips (and there's a one-click pathway for that common case). Each Trip gets its own row on the report, and each Trip has its own ID number printed on that row. The request I received was to make each printed ID a hyperlink to the data-entry page for the Trip.

Generally, people like to believe that "you get out what you put in"; that is, that the more effort you expend, the greater the reward. Baloney. I received more praise for implementing the hyperlinks than I have for any other feature in many moons. I spent months porting the app from VB4 to Python. In the process, I wrote an entire Object-Relational Mapper, including a DSL for processing data Sets, a mechanism for creating portable, early-bound Expression objects, and built-in analysis tools. I also wrote a web application framework, and an abstract Business Objects model independent of our specific business process. From the point-of-view of my users, all of that is par for the course—either completely expected, or completely obscured from their understanding. The response is decidedly underwhelming.

Total effort to implement the hyperlinks: open HTML file #1, select text, copy, open HTML file #2, paste. No reboots, not even a reloaded module. Perhaps 3 minutes if I throw in a test on the development platform before it goes "live".


  • "Do that, and wait for the cries of 'Hallelujah' from our users."
  • "Bob's a genius."
  • "We're not paying you enough." (Really! I have the email.)
  • "An answer to prayer."

:roll: Unbelievable.

The issue, of course, comes down to pleasing your audience. There's a meme among working software developers like myself that you should write code worthy of the giants of computing. Larry Wall's quote ("The three chief virtues of a programmer are: Laziness, Impatience and Hubris") is often interpreted to mean "write code you want to show to your friends", meaning other developers. But let's face it: very few developers are going to be looking at my code, one or two of them are going to have any response to it, and 10% of them will be in a position to affect my life based on their opinion of my code. The return-on-investment vanishes rapidly.

Does this mean I should stop writing software which pleases gurus and concentrate solely on my users? No, because I fibbed a bit. There is at least one developer whose favors I want to court: my future self. So I do what I need to do to keep myself and my team happy. The true role of a software architect is learning how to please your developers (even if it's only you), your users, and management. Do that well, and the rest follows, often with a simple cut and paste. And if you're a solo developer, learn how to reward yourself for the Herculean code nobody but you will ever appreciate.



Permalink 01:38:02 pm, by fumanchu Email , 33 words   English (US)
Categories: General

Free clip art

The New York Public Library has made their digital collection publically available.

Via Todd Blanchard at IWETHEY.


Permalink 10:47:31 pm, by fumanchu Email , 213 words   English (US)
Categories: General

Amor is 25 years old!!!

I can't believe I'm the first staff member to blog about this--you all were at the party!

We headed off to Anthony's Fish Grotto at lunchtime today to celebrate the 25th anniversary of Amor Ministries! Our staff, some old friends, and several board members were present to tell some great stories about the early days, and to give congratulations to Scott and Gayla Congdon, our founders, in particular. We also heard a great report from Scott about the last board meeting in El Paso, and how thrilled they were when they recounted all of the milestones we attained this past year:

  • We built our 10,000th home.
  • We had over 22,000 participants working in Mexico.
  • We became a $5 million company.
  • We established a new "main camp" in Tijuana.

...and many more.

I want to take this opportunity again to thank Scott and Gayla for their years of dedication--to those about whom nobody else cared--this manifests the love of Christ more powerfully than any speech or sermon. Thank you for modeling Christ for me directly. And a big thanks to all who have lived, worked, and donated time, energy, money and labor to the building up of the church in Mexico. You are part of something great!


Permalink 10:02:39 pm, by fumanchu Email , 43 words   English (US)
Categories: IT

Some website testing links

Sites I want to look at in more detail when I have time:

Permalink 03:58:54 pm, by fumanchu Email , 750 words   English (US)
Categories: IT

Ajax differences between IE and Firefox

It had to happen sooner or later: I've been singing the praises of Firefox for quite a while now, and eventually I had to come across something that Internet Explorer does "better". [Update: it doesn't really, if you tweak Firefox. See last paragraph.]

That "something" is an asynchronous XMLHttpRequest, which is all the rage lately. Jesse James Garrett calls it "Ajax", which is as good a name as any, and one that I think will stick. I had the idea to try writing a webpage that would use async javascript + XML to stress-test a website, using only a browser. The initial prototype for that page follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 %s//EN"
<html xmlns="" xml:lang="en" lang="en">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Frontload Stress Tester</title>
<style type='text/css'>

.graphpt {
    position: absolute;
    left: 0px;
    top: 125px;
    width: 1px;
    height: 0px;
    background-color: red;


<script type='text/javascript'>

if (typeof(XMLHttpRequest) != "undefined") {
    http = function() {return new XMLHttpRequest();}
} else {
    try {
        new ActiveXObject("Msxml2.XMLHTTP");
        http = function() {return new ActiveXObject("Msxml2.XMLHTTP");}
    } catch (e) {
        try {
            new ActiveXObject("Microsoft.XMLHTTP");
            http = function() {return new ActiveXObject("Microsoft.XMLHTTP");}
        } catch (E) {
            alert("Your browser doesn't support XMLHttpRequests");

totaltime = 0;
semaphore = 0;
loadlimit = 0;
url = "";

function makerequest() {
    var h = http();
    var start = new Date();
    starttime = start.getTime();
    h.onreadystatechange = function() {
        if (h.readyState == 4) {
            var response = h.responseText;
            var d = new Date();
            thistime = d.getTime() - starttime;
            document.getElementById('each').value = thistime;
            document.getElementById('eachbar').style.width = thistime + 'px';
            // Move one of the graph points onto the graph
            point = document.getElementById(semaphore);
   = semaphore + 'px';
   = thistime + 'px';
            semaphore += 1;
            totaltime += thistime;
            document.getElementById('avg').value = (totaltime / semaphore);
            document.getElementById('avgbar').style.width = (totaltime / semaphore) + 'px';
            if (semaphore < loadlimit) makerequest();
    }"GET", url, true);

function stresstest() {
    totaltime = 0;
    semaphore = 0;
    url = document.getElementById('url').value;
    loadlimit = parseInt(document.getElementById('load').value);
    for (i=0; i < loadlimit; i++) {
        point = document.createElement("div");
        point.className = "graphpt"; = i;

// -->

Load: <input type='text' id='load' value='10' size='4' />
URL: <input type='text' id='url' value='http://localhost/mcontrol/index.htm' size='44' />
<a href='javascript:void(stresstest())'>GO</a>
<br />
Each (ms): <input type='text' id='each' value='' size='6' />
<div id='eachbar' style='background-color: #66FF66; border=2px solid black; width: 100px;'>Each</div>
Average (ms): <input type='text' id='avg' value='' size='6' />
<div id='avgbar' style='background-color: #8888FF; border=2px solid black; width: 100px;'>Average</div>

If you don't care to wade through that, it requests a URL n times. You get to tell it n and which URL. The idea was that, although Javascript doesn't do true threading, it at least allows asynchronous processing. I thought it might be possible to make multiple HTTP requests, and have the callbacks processed asynchronously (which doesn't work, by the way, even with setTimeout). I would then time each request (placing the start time in the callback closure), and dynamically show the times on-screen.

It turns out that IE and Firefox time quite differently. For most IIS pages, IE takes 10 or 20 milliseconds to fetch a minimal page, while Firefox takes 40 to 60 ms fetching the same page. With larger pages, the difference continues to be about 40ms per page. I can only assume at this point that the difference lies in the external objects used to make the requests: my IE uses the Msxml2.XMLHTTP ActiveX object, while Firefox uses the XMLHttpRequest builtin. Now the interesting part is that the gap between Firefox and IE narrows when I serve the same pages via Apache2 on Windows, instead of using IIS. IE takes an average of 7ms for the minimal page, and Firefox takes 16ms. For another, larger page, IE takes an average 227ms, while Firefox takes 233 (a difference of about 6ms, not the 40ms we had previously).

Hmmm. More tests to come...

Update: Okay, after making the pipelining tweaks described here, Firefox gets down to a more reasonable 20ms per minimal page on IIS; the Apache speeds are unchanged. Somebody should make those tweaks the default, given the buzz around Ajax these days.


Permalink 03:33:21 pm, by fumanchu Email , 344 words   English (US)
Categories: IT, Python, Dejavu, Cation

Where to put the locks

I've got to add access control to "Mission Control" (our main business application), and I cannot decide where to do it.

There are two main components: a UI (built on a UI framework, Cation), and a Model layer full of business objects (built on an Object-Relational Mapper, Dejavu).

Part of me wants to build the controls into the business objects themselves, since that's really what needs to be protected. I don't care if someone can access a page if they can't see any data on it (or add any data through it). It wouldn't be difficult to enforce, because all the business objects already subclass dejavu.Unit, the base class for the ORM. The downside is that Dejavu doesn't currently have any concept of users or access controls. Any user context, therefore, would have to be passed into Dejavu from outside. This wouldn't be too hard, since every Dejavu session checks out its own Sandbox object--I could just stick a reference to the access-control library into the Sandbox. I'd probably end up leaving the default Sandbox as is, and write a new SecureSandbox class, then decide between the two via a config parameter.

Writing the locks into the Model would be nice, because, in general, those change less often than the View. When new features are added, having the locks in the View code means a higher probability of forgetting to test for permission.

It would also be nice for management by end-user admins--they tend to understand "you can see Mission Trips but not Projects" better than long lists of event descriptions like "Show the Zip Code of the Primary Addressee on a Group Scheduling Report (but not a Group Scheduling Calendar)".

But another part of me wants to put the locks in the View. It would allow finer-grained permissions, and allow locks on behaviors which don't involve persisted business objects. It would also be better-integrated, since the View layer already interacts with authentication code in the webserver. There's also a lot of precedent, in that most ORM's don't manage permissions.



Permalink 10:29:36 am, by fumanchu Email , 97 words   English (US)
Categories: IT

Tim Bray's Northern Voices keynote


Things I want to remember:

  1. Listen first.
  2. Those who are read by many write often.
  3. Correct yourself. Classic journalism can't do this. We can. Updates go at the top of the article, so RSS feeds are sure to show them.
  4. Don't make stupid spelling mistakes. Spellbound for Firefox, anyone?
  5. Be brief. cf Stephen King's Ten Minutes.
  6. Blogs are public and the Internet never forgets. Just be careful--don't tell secrets.
  7. Blogging is much more about listening than talking.
  8. Be intense. Be sincere and authentic. Never lie.
Permalink 10:00:30 am, by fumanchu Email , 631 words   English (US)
Categories: IT, Python

The DIY "Antipattern"

I don't get it. I keep seeing people try to help software developers by telling them to stop trying (not trying to pick on you, John). There is a consistent trend to answer tough questions with, "someone has already written that, go use theirs". When did that start, and why do I keep seeing it?

I should probably explain why I find it a hard pill to swallow. Quite simply, I have strong recent experiences where I learned far more about a technology by building it than by using someone else's. This is certainly the case with my two "main" frameworks right now, Cation and Dejavu. Cation is a web application framework, and Dejavu is an object-relational mapper. In both cases, there are already many Python implementations, each with their own quirks and design decisions. Part of what drove me to write my own was that, given a choice between a dozen or more viable Python web app frameworks, I didn't have enough information to decide between them. Writing my own gave me that knowledge. I now feel I have the ability to judge which one I would go with in a new project, because I've hit the roadblocks myself and overcome them. Just as importantly, I know my own data better and can better match up the feature set that supports our requirements.

I'm the only programmer here at Amor, so I have to write a little bit of everything. I have to say that in those cases where I do go with someone else's code, I almost always learn it and live with it, for good or ill. Nothing ever gets fixed, it only gets worked around. Real fixes have a much higher cost--when it's Someone Else's Code, it's Somebody Else's Problem.

If software development is a craft, then we have to allow the apprentices to try things out. Maybe you, dear reader, got all the training you'll ever need in college, where you were forced to write compilers and parsers, full UI's and databases. But I didn't. I'd still like to learn more.

Fu's First Law: Everything's hard 'til you've done it once.

Now some synchronicity: Patrick Logan linked me just now to James Robertson who linked to Jeff Atwood, who says

...if you do want great software, you have to let the developers own what they're building.

The converse is also true for me: if you want great software, you have to let the developers build what they're owning.

Do I think this is always true? Of course not. I'm not advocating a glorified "Not Invented Here" syndrome. There's no need for me to write Python all over again (however, I needed to hack bytecode for Dejavu). I don't need to write mod_python all over again (however, I needed to inspect its source code on more than one occasion for Cation). My point is that context is all-important, and recommending to someone that they skip the learning process strikes me as irresponsible, if you do not first inquire about that person's context.

Update: and now I read Jeffrey Shell: "But in my experience, the work required to do a good integration in a lot of these systems seems to be about equal to writing one from scratch."



<< 1 ... 16 17 18 19 20 21 22 23 24 25 26 >>

April 2018
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          


The requested Blog doesn't exist any more!

XML Feeds