资源说明:Before Github, programmers would link to code samples. Here are a few from my vault
Some Old Source Code
===
*Before Github, programmers would put links to code samples in their resumés. Here are some samples I used to provide. Back in the day. Before electricity. And yes, this is the actual text I used to introduce each snippet at the time.*
**Interview Answer**
Erich Finkelstein introduced me to the "balancing rocks" interview question. It's a math puzzle of the style you'll find at techinterview.org. The nice thing about rock balancing is that it isn't an "aha" problem: there are several solutions of varying quality, so candidates have a great chance to show off their smarts by asking smart questions and considering various aproaches.
I'm not going to describe the math puzzle, but lately I've been asking candidates to check the correctness of their answers the nerdy way: by writing a program that checks it for them (ok, I usually don't have a lot of time, so I ask the candidate to write the algorithm out). In adherence with the Golden Rule, here're a few versions I whipped up in a few minutes (each) that do the job.
**Java Temporal Entity Relationship Modelling Framework**
These classes are part of a personal research project. I don't want to say too much about the project: the point is to create a working application, not a research thesis. I arbitrarily grabbed a few source code files that I happened to be editing when I decided
asynchronously to update this page. They aren't complete and I guarantee they will have changed by the time you read this.
Anyways, the idea exposited by this source code is that this application is event-centric: instead of investing 80 percent of the architcture in the domain model and 20 percent in the transactions that modify the domain, this application invests 80 percent of the architecture in the events that cause changes to the domain ("Domain Events") and only 20 percent in modelling the domain itself.
For more information on this subject, try doing a web search for "
Temporal Database". I'm grateful to Camiel Wolsing of CriSys Limited for suggesting this area of interest.
TestDomainEvents.java
|
Preliminary HttpUnit tests for Domain Events.
|
DomainEventCommand.java
|
"Commands" are like little servlets that live inside the UI and perform actions, something
like Struts actions. These are not Domain Events: this particular command generates a Domain
Event and attempts to implement its writes.
|
DomainEventFactory.java
|
A preliminary factory that builds Domain Events and uses reflection to populate them. There is some
preliminary pattern matching available as pre-validation of domain event parameters.
|
TDomainEvent.java
TAbout.java
|
Some handy interfaces. TAbouts are used for answering whether operations are allowed,
like rich error messages. TDomainEvents are events that take place in the subject
domain (in an HR application, think "Hire" not "Add Row to Employee
Table").
|
**Adding Continuations to the Java Programming Language**
These classes are part of another personal research project. My interest was in adding continuations to the Java Programming Language so that web applications could be written in Java using a Cocoon or Seaside style of programming. The benefit is that much of the session state management in a modern web application simply goes away, making software development simpler and more reliable. And as an added bonus, the new window, back button, and bookmarks all work all of the time, eliminating my major irritation with treating web browsers like a desktop GUI.
This "Big Idea" is that in a standard web application we cannot obtain information from the user in the middle of a method: we therefore cannot model a series of UI steps in a single method. Although some folks feel that isn't a good idea, the fact is that lots of web applications do have a series of sequential steps: try checking out of almost any e-commerce site.
The basis of the system is to rewrite Java methods so that they become 're-entrant': they become a loop enclosing a big switch statement, with all state stored in a big vector of parameters. The method can be restarted arbitrarily by passing in the current state and a label. The sample classes handle some of the Abstract Syntax Tree transformations required to flatten the tree into one level so that it can be rewritten as a switch statement.
The basis for the transformation is that the Java byte codes are parsed and mechanically transformed into an intermediate language. Certain special forms that would be keywords are represented as special static methods of a dummy class: those methods are turned into special forms in the intermediate language. In a tradition dating back to 1957, the intermediate language has an ascii representation featuring Lots of Interesting and Special Parentheses. That representation appears often in the test cases: it also makes it easy to decouple testing of the transformations from testing of the byte code parsing.
LetCallExpander.java
|
Certain patterns in the AST are rewritten to simplify optimization and transformation.
A let/call/cc form is a place where a method can be restarted. In a web application, every
form presented to the user is a restartable place in the computation. The let/call/cc special form
names the restartable place so that a form can be submitted back to this place in the computation.
This class transforms the code into a sequence of steps featuring a label that can become the
target of the enclosing switch statement.
|
CallExpander.java
|
The inverse of let/call/cc is a call statement. This is where one piece of code invokes a named
continuation. The sample code transforms this into a restartable computation: it looks just like
let/call/cc without the name. That's because the model of computation is that of coroutines
that yield to each other: the process is symmetric.
|
YieldExpander.java
|
The yield special form actually transfers execution to the named continuation. It is also
expanded into a simple sequence.
|
SetBangBeginFlattener.java
IfFlattener.java
CompositeEntryFlattener.java
|
Lots of language constructs add scope to the AST. Flatteners rewrite the code using GOTOs so that it has a single
scope with all of its variables hoisted.
|
**Code Generation for Struts Development**
When working with large Struts development projects, managing changes to the struts-config file and your action classes is essential. I developed a collection of code generators in XSL that transformed a struts config file into a collection of action classes, interfaces, and business logic abstract base classes. This is useful if you have a tool automatically building the struts-config file from a source like a spreadsheet. Automatic generation saves a little coding time up front, but its real benefit is when the design goes through the inevitable refactoring: the classes are automatically updated and strong typing catches any places where business logic classes have not been updated. Thus, the combination of code generation and type checking makes refactoring easier.
actions.xsl
|
In conjunction with a build step that applies this XSL sheet to the struts-config.xml file,
this generates a collection of Action java classes automatically. Each action class forwards to a Delegate class that actually contains
the business logic. The idea is that a number of different actions might be handled by the same logic class. A
special attribute added to each element in the structs-config file identifies the appropriate Delegate.
The Action classes are responsible for forwarding action requests. A nice side effect for strong, declarative
typing enthusiasts is that each forwarding call is strongly typed, documenting and enforcing the proper form bean's type in Java.
|
delegate-interfaces.xsl
default-delegate.xsl
|
Custom attributes in the struts-config file identify the business logic delegate that is to
handle each action. These xsl style sheets generate a Java interface and an abstract base class
for each delegate. There is a many-to-one relationship between actions and delegates, so each
delegate gets a handleActionName method for each action it handles. The style sheets
ensure that the handler method takes the correct form parameter (if one is needed) and returns the
correct bean (if one is neede for viewing).
|
IEntityDelegate.java
ActionEntityDetailsGeneralTab.java
|
Sample files generated automatically.
|
**Denumerables in Ruby**
I experimented with the Ruby programming language. While it doesnt have the power of Lisps macros, it does have first class closures (you can even use the lambda keyword) and support for continuations. All this in a true object oriented language with support for operator overloading!
**Wireshooter in PHP**
Wireshooter was a database backed web site that published news and sports photos for download by magazines. Photographers uploaded their photos using a standard web browser, and then Wireshooter periodically rebuilt a static web site from its database. Here is the complete and uncommented source code, now available via Gnu Public License.
Basically, there were two servers: a public server running on an ISPs high speed line, and a private administration server running on our own system. The public server served up static files, and the private server ran Apache with mod_php. The files you see here all were on the private server.
The architecture was loosely MVC. The PHP pages accessible from the admin page were the controllers, the production site was the view, and the PHP include files were the model, handling control of the SQL database.
/private/admin/index.html
|
The administration page. This is the page I used to manage the
site. The site was running on a
public server, but there was no access for the public whatsoever.
|
/private/admin/resetdb.php
|
Oh no!
|
/private/upload-image/sports.php /private/upload-image/filmfest.php
|
The site was divided into two main databases, one
for sports images and one for filmfest images. Separate pages were
used for uploading sports and filmfest images. Its easy to
build a generalized upload page that can upload to any database,
but this was easier for the photographer to manage.
|
/private/grind/grind.php
|
On a daily basis, you could grind the database out
to static HTML files. This would also create scaled down previews
of the images with copyright banners attached. Static files were
jillions of times faster than dynamic pages, and disk space is
free, even on the ISPs server. The static files would not be
public, however you could navigate them all and make sure
everything was Ok. This also protected the public server in case
of a crash while grinding.
|
/private/xml/mirror.xml
|
The structure of the production site was defined in this XML
file.
|
/private/grind/mirror.php
|
When you were satisfied with the static site, you would
mirror it to the production site using FTP. This was
very loosely M/VC: The work was done by
/private/grind/mirror-action.php.
|
The PHP files that handled uploading images:
|
/private/upload-image/upload-action.php,
/private/upload-image/sports.php,
/private/upload-image/filmfest.php
|
The include files for the site:
|
/private/required/admin.php,
/private/required/blackboard-protocol.php,
/private/required/blackboard.php /private/required/class.php,
/private/required/error.php,
/private/required/image-schema.php /private/required/simplify.php,
/private/required/sql.php,
/private/required/table-schema.php /private/required/TAbstractRootPage.php,
/private/required/TContext.php,
/private/required/thumbnails.php /private/required/TMirrorGrinder.php,
/private/required/types.php,
/private/required/upload.php /private/required/wiregrinder.php,
/private/required/wireshooter.php,
/private/required/wiretemplates.php
|
**Wireshooter in Java**
Wireshooter was a database backed web site that publisheed news and sports photos for download by magazines. Photographers uploaded their photos using a standard web browser, and then Wireshooter periodically rebuilt a static web site from its database. I wrote a prototype in Java, then re-wrote it using PHP. Here is a class from the Java prototype:
ColumnGrinder.java
|
This class creates indices for the different values in a column
of a table. For example, if the schema includes a column named
"Sport," this class builds indices for each sport.
Compare this to the PHP version.
|
**MetaCard Configuration Wizard**
On a large and very successful software tool, we needed a wizard for configuring JProbe's complex scripts. I wrote a fully functioning wizard using MetaCard, a cross-platform implementation of Apple's old HyperCard authoring tool. It took me three days or so to write and debug the complete wizard. We didn't end up shipping the MetaCard wizard: for 'strategic' reasons the wizard was re-written from scratch in Java. And no, it didn't take three days to build and test the re-write.
wizard.mc.txt
|
Excerpts of the MetaCard script for the Configuration Wizard.
|
**C++ Source Code**
These are some of the C++ general purpose classes in my 'toolbox'. There's a heavy "Effective C++" bias. This set is everything you need to implement Hash Sets where each object has a primary key (unique in the set) and a secondary key (not necessarily unique). To convert this to a Map (in Java terminology) or Dictionary (SmallTalk terminology), an adapter is used (the equivalent of Java's Map.Entry).
**Scheme/Lisp Web Application Platform written in Java**
Here's some Java I wrote when building NAVajo and Firestorm (both of which are 100% Pure Java). NAVajo was a system which built static web pages from HTML pages with an embedded scripting language called 'MendelScheme'.
Firestorm was a web application server which used a Scheme/Lisp dialect as a scripting language to build dynamic web applications.
To make it perfectly clear: I wrote the interpreters for both MendelScript and Firestorm in Java, and both of these were used to build production web applications. Today we have J2EE, JSPs, ASPs, and various other web application platforms. But in 1996 these applications were cutting edge.
DilutedInterpreter.java
|
A sparsely commented excerpt from Firestorm's source. This Java
class is the core interpreter for the Scheme-based server side
scripting environment at the heart of Firestorm. It is similar to
Curl.
|
AbstractMember.java
|
An interface from NAVajo (Firestorm's predecessor). Glancing
over it quickly, you can see that at the time I was enamored of:
naming conventions; heavy use of the envelope idiom (thus the
yourself method); container inheritance (analogous to event
handling in a GUI); and dynamic typing (the strategy idiom).
|
MemberBuilder.java
|
An implementation of the factory pattern in NAVajo.
|
TEnglish.html
|
An early template page for NAVajo, showing the Smalltalk-like
syntax. NAVajo renders template files like this into HTML. Compare
to navajo-scheme.lisp.
|
**Scheme Source Code**
The following examples are Scheme used to test the core Firescript interpreter. They were displayed on a virtual command line and do not reflect any web server functionality:
bad-recursive.lisp
|
A recursive implementation of factorial which is not
tail recursive.
|
factorial.lisp
|
A properly tail recursive implementation of factorial.
|
no-tail-factorial.lisp
|
An implementation of factorial which is not tail
recursive.
|
benchmark.lisp
|
Something which chews up enough cycles to be worth timing.
|
continuation.lisp
|
A test for call-with-continuation. Enough to convince me
that a 30% performance hit wasn't enough to justify the awesome
elegance of continuations. [Note from 2002: The problem was my
implementation: I was not clever enough to make continuations as
cheap as a Long Jump.]
|
freeze-and-thaw.lisp
|
Demonstrates the power of combining macros with raw lambdas to
implement algol thunks.
|
hello.lisp
|
Disk space is cheap.
|
let.lisp
|
Tests the let macro. Especially important, because the
implementation changed several times. In proper Scheme, let has a
specific macro definition. Originally, I had a custom handler for
let because I hadn't implemented macros properly but I wanted to
use let. Then, I implemented macros and made let a macro. Finally,
I implemented a lot of optimizations to ensure that let wasn't a
performance hit.
This is why I'm aggressive about regression testing. Over the
course of a development cycle, implementations can change quite a
bit, and it's crucial to know when and if you inadvertently break
something.
|
map.lisp
|
Another regression test. map changed from being a built
in function to being a generalized variable.
|
even.lisp
|
Determines whether an integer is even. Puzzle for people new to
Lisp: is this tail 'recursive'?
|
no-tail-even.lisp
|
An implementation of even? which is not tail
recursive.
|
stack-inversion-example.lisp
|
Tests the generalized variable facility in Firescript.
Borrowed from Common Lisp.
|
Firescript Source Code
---
The following examples are from the Firestorm application server. Firestorm was a web application server I wrote in 1997 which used a Scheme-based scripting language to build dynamic, user-centric web applications.
**XML and User Preferences**
This is part of a small module that demonstrates how to track user preferences. In this case, users of an online application can indicate whether they prefer English or French text, and whether they prefer graphics or text only (the demonstration was composed when 56K modems were uncommon):
sartz.xml
about.dtd
|
An XML file containing language attributes. This module
rendered the XML as HTML.
|
display-preferences.lisp
|
This displays a preferences page for the user. Notable features
are: recursively embedding Scheme and HTML inside each other; use
of this-session dictionary and generalized variables; and
the ability to 'call' this page from any other page.
|
sartz.lisp
|
The Firescript page which handles the display of sartz.xml.
This follows the "MVC" pattern: the logic is embedded in
this page, while the model is embedded in the XML page. And of
course, the XML could be 'repurposed' in other forms.
|
validate-preferences.lisp
|
A helper function encapsulated in a separate file. Shows that
you can structure Firescript applications on a server.
|
**NAVajo update**
The NAVajo system was a predecessor to Firestorm. I reimplemented the application in Firescript to demonstrate the newer, more Scheme-like syntax. Of course, Firescript offered much more power than the original "MendelScheme" scripting language.
**Displaying Dynamic Collections**
This is part of a small module that demonstrates how to display collections of things which can change. In this case, photos of Bryan Donald Bartle are dropped into a folder and Firestorm displays them in a crude photo book:
List.lisp
|
The file which completely describes the list of images. Note
that (unlike the previous example) display code is intermingled
with hard coded information about where to find the photos and
what they are about. This demonstrates that Firestorm supported
hacking out quick solutions as well as structured designs
:-)
|
detail.lisp
|
This displays a single photo in a simple page.
|
**SmallTalk Binary**
The only SmallTalk I can lay my hands on is an implementation of Streamized Programming for DigiTalk SmallTalk I wrote in 1983. Good luck filing it into your image!
VSTRM.CLS
|
A class which implements streamized programming, which
uses delayed evaluation to allow extremely high level abstraction
of infinite streams such as 'integers', 'primes', &tc. Save it
to your system and file it in.
|