...extracting a re-usable framework after the fact struck me as interesting because that's really what's happened with Leonardo. Two years ago, I wrote a little wiki-like script in Python in order to enable editing of content on jtauber.com from a browser. I then decided to expand it just over a year ago to include a blog. Now, as more features are being requested, an underlying web framework is emerging that could very well be useful outside of running a wiki or blog.
The same thing happened with Cation (a web framework) and Dejavu (an ORM). I was tasked with rewriting our core business app—two years ago, it was a procedural CGI app written in Visual Basic 4! When I rewrote the whole thing in Python, I started by isolating Cation+Dejavu into their own layer. After about six months I then separated Dejavu from Cation. In addition, I made a middle business-objects layer called "EnDue", which the final app, "Mission Control" is built on. There's also a wiki-like app called "Junct" which I built on top of Cation and Dejavu. So the tree currently looks like this:
[Cation] [Dejavu] \ / \ / [EnDue][Junct] | | [Mission Control]
I've also got "test apps" for Dejavu and EnDue (well, I'm still writing the one for EnDue...I think I'll model the business of the beard-and-stone salesman from "Life of Brian" Any good names for such a business?).
Anyway, the real point I want to make (and have made before) is that I'll probably replace Cation with another web framework sometime this year...but I wouldn't have known which existing framework to pick if I hadn't written my own first.
"The steadfast love of the Lord never ceases, His mercies never come to an end; they are new every morning; great is your faithfulness." Lamentations 3:22-23 God's steadfast love has been the strong link that has kept me going for my ___ years! (Can't tell all my business!) I'm celebrating God's mercies in helping me live a long life dream of ministry. I'm celebrating God's faithfulness in keeping me healthy & strong...and for keeping me laughing! April 29th is a day to remember!
This is Tito... Tito is very special to many children here and abroad. If a child has lost all hope for his future due to poverty, abuse, or neglect. Tito tells them in a language familiar to them that God is their hope and their future. Tito even has a fan club that follows him around. Helping in his shows and be blessed in the process. At a Child Abuse Center here in San Diego. Tito is their friend. Showing them spiritual truths and bringing laughter in what could have been a very sad day! Tito and I have been doing this for many years. The stories of how many children have come to know God's love is great. All I know that even when a child enters with a sad, long face...they always seem to leave with a smile that lights up any room.
So I went out again yesterday and this time we brought someone with gear. Ropes. Ropes let you climb higher, more vertical, and a lot crazier than without. So, I climbed higher, more vertical, and a lot crazier than last week.
Repelling was a blast. There is something about standing backwards on the edge of a 25 foot cliff and letting your body fall backwards. It was soo much fun, then when we repelled to the bottom, we got to ascend to the top. And do it over and over again for about 3 hours. The guys in the pictures are my friend Ben Kotnick, and his brother Dan. Dan is a very knowledgeable and safety conscience climber, which was great for my piece of mind, since this was my first experience with belaying, repelling, and toproping. Yahoo!
Other than the feel of climbing, my most vivid memory from yesterday was when Dan was explaining the braking method for repelling. He was showing me how to hold the rope in order to brake. As we are standing on the edge of the cliff he said, "This is your braking hand, if you let go of the rope with your hand, you will perish." Not, "Don't let go of this rope because you will get hurt". No, it was "...you will perish". I didn't let go of the rope!
See if you can guess which verses (from the New Testament) begat the following:
Which enters, the opening of a man does not give him the other way around for pigs, but this sae of the relative opening, that gives to shutdowns the pigs the other way around.
The legend you to that the truth is left here, not a rock in another one; everything is in the game of the reduction.
Loaded therefore him, where the brothers, to offer due to the tolerance of the God, their bodies have taste of alive victims, those know him and the God of the execution -- in whom it is his mental Anbetung.
It would appreciate Christian and the energy of the relative Auferstehung and the friendship of the division in relative pain would know and as in the relative one it died therefore and, the method or other that takes to traverse with the Auferstehung of the inoperative men.
I set up all this:
- The old Merlin phone system, which was removed in favor of...
- The new Avaya digital phone system, which talks to the phones in our San Diego office over...
- The new T1 router, which replaces the old DSL, and serves...
- The LAN clients, via this hub, firewall/router, and switch, which have a couple of green cables running to...
- The new VPN server, which I described how to set up here and here.
Bah. I can't design my way out of a wet paper bag when I get rushed, and I've been awfully rushed the last month or so.
The problem is update triggers. Our business (like every other) has tons of things that should happen when data changes. For example, when one of our clients decides to arrive a day earlier, that affects lots of business decisions. The people who make those decisions need to be notified, usually by email. Other, dependent business objects need to have their data updated. The very act of changing the date needs to be logged.
OK, that's not the real problem yet. The real problem is finding out when to do all of these activities. My naive first approach was to simply perform all of these side-effects whenever the FirstDate property of a MissionTrip unit changes:
def __set__(self, unit, value): if value != unit._properties[self.key]: unit._properties[self.key] = value self.fire_triggers(unit, value)
This is straightforward, but not very flexible. I put myself in a corner recently over this: the FirstDate is calculated based on a set of TripDate objects. When a user submits the MissionTrip web page, they might add three new TripDate objects—each one triggers a recalculation of the FirstDate property, and I ended up with three separate records in the log, along with three separate email notifications!
The local fix would be to not put a trigger on the TripDate objects, and to manually recalc the FirstDate. Wherever needed. There goes the whole point of objects.
What would be better would be a trigger that could fire at the end of the session (say, the web-page submit) instead of at the point of modification. But I can't figure out a clean way to do that. I worry that I won't remember to call session.cascadeAllTriggers() at the end of some submit handler, and I won't notice that fact for some time, since all of those activities are by nature side-effects. Not to mention the corner cases where I need to fire triggers before the end of the session.
Hmmm. I'd like something more declarative than imperative, I think.
What a messy part of domain modeling.
This is an account written by Shawn Passwaters regarding one of our adventures...
04.01.05 "What a bunch of jerks." Ryan and I were walking off the last hole of a very boring disc golf course and it was his decisive manner which caught my attention. I'm used to him being generally positive about his disc golf experiences, so this statement caught me rather unawares.
"Who do ya' mean?"
"Those guys. I just waved and said hi and they just totally blew me off without even looking at me."
I told him that I've found most disc golfers exclusive and predominantly, arrogant nerds and just as we were about to launch into a really great rant, Ryan noticed an MP3 player sitting beside a lamppost. I told him it would really suck to lose my MP3 player and he wondered aloud if it might belong to the last group we passed. We didn't like their behavior, but no one deserves to lose their MP3 player. We had already backed out when the group walked up to their cars, so I rolled my window down to yell to them.
They're apparently deaf or incredibly apathetic about talking, choosing to communicate by waving their hands about in a vicious, hurried manner. "I'm such a jerk," Ryan mumbles. "You are," I say, "but what's your point?" "Dude, they're deaf." I could see his reasoning. We had just spent the entire walk to the car casting disparaging remarks to the wind regarding this group and now we find out they're deaf. "Dude, you are a jerk," I say as we both start laughing nervously at our own callousness.
I should have just driven away at this point, but as I watched them pack up their cars, signing to one another the entire time, I started babbling without missing a beat. My hand shoots up and I'm waving and words are pouring from my mouth. Why am I asking this guy if he's lost an MP3 player? He motions to his ear that he can't hear me and I say louder while making the universal hand-cupping motion for headphones over my ears, "Did you lose an MP3 player?" I point to the lamppost and he obediently grabs the MP3 player and starts back towards our truck. I stop him like he's the idiot, waving him off and yelling, "They're not yours?" No, he shakes his head and then it hits me...the entire group is deaf.
I've just asked a deaf man if he's lost his MP3 player.
I can feel my stomach churning with a nauseated embarrassment. I wave to him weakly and mouth that I'm so sorry as I skulk away with my head barely showing over the top of the dashboard of the truck. "I'm the biggest jerk in the world." I hear Ryan's near-hysterical laughter, then I notice that I'm laughing, but it's the laughter of a man who sees the irony of laughter in the face of death, but can't fathom his own demise. It's a fool's laughter and it frightens me, but it feels oddly comforting.
I've just asked a deaf man if he's lost his MP3 player.
"Dude, don't sweat it," Ryan croaks out amid his dying laughter, "it's not like he can tell any of his friends about this."
"How do you figure?" I say.
"Get it? He can't tell anyone."
"Your're sooo burning in a special place in Hell for that one."
Can you see wich stamp is "missing" and why?
I also thought the inclusion of the "&" stamp in-between Y and Z was pretty funny—I sing the ABC song in my head every time I see it.