What is Borges?

B

Bill Atkins

Can someone please explain to me what Borges does? Its home page
isn't very descriptive, but I get the feeling that it's extremely
neat.

- Bill Atkins
 
D

Dick Davies

* Bill Atkins said:
Can someone please explain to me what Borges does? Its home page
isn't very descriptive, but I get the feeling that it's extremely
neat.

Follow the links to the SeaSide docs, they have pretty good explanation
of the principles.

<almost-on-topic>
I still can't get my head round continuations - does anyone have a good ref?

All I've seen so far is either 'look, we can do goto' or
'look, here's Borges', which is a learning curve so steep it starts to
look like a wall....
</almost-on-topic>

Few Borges specific links :

http://homepages.ihug.com.au/~naseby/42.html

Eric's rubyconf stuff:

http://www.zenspider.com/dl/rubyconf2003/Borges.pdf

And there's an Iowa (which is also continuation ish , and a cousin of SeaSide)
intro at:

http://beta4.com/iowa/newtutc.html

[ I got the impression that Borges is still a little leaky, though I haven't
had the cohones to try it out much yet ]
 
J

Josh Huber

Dick Davies said:
I still can't get my head round continuations - does anyone have a
good ref?

All I've seen so far is either 'look, we can do goto' or 'look,
here's Borges', which is a learning curve so steep it starts to look
like a wall....

I found reading (and understanding) this page:

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc

helped quite a bit. Specifically, the final implementation by Avi
Bryant which uses callcc should help.
 
W

wilkes joiner

It is nothing short of revolutionary. It feels a lot more like
writing a traditional GUI app than an Action based, Request and
Response app. I was just not able bring my self to write an app in
Seaside because of Squeak. Don't get me wrong, Squeak is great, but I
have been wanting a Ruby port for some time.

Check out the SushiNet example, and start playing around with it. The
is the only way to understand how it differs from other web app
frameworks.

Cheers,
Wilkes
 
K

Kirk Haines

On Fri, 7 May 2004 19:58:29 +0900, Dick Davies wrote
And there's an Iowa (which is also continuation ish , and a cousin
of SeaSide) intro at:

http://beta4.com/iowa/newtutc.html

Iowa doesn't use continuations. It takes the everything-is-an-object
approach and operates under a traditional request/response cycle. It
features seperation of content from code. Content is plain old HTML with
some simple markup additions for controlling the dynamic parts, and code is
just plain old Ruby. It can be used for full on applications as well as
simple dynamic pages as I have created an extension to it that lets one map
URLs to specific content objects.

I've finally gotten a start to the tutorial for it up:

http://enigo.com/projects/iowa

That whole site is actually implemented under Iowa, BTW.

There's also a rubyforge project for it:

http://rubyforge.com/projects/iowa


Kirk Haines
 
J

Julian Fitzell

Dick said:
<almost-on-topic>
I still can't get my head round continuations - does anyone have a good ref?

All I've seen so far is either 'look, we can do goto' or
'look, here's Borges', which is a learning curve so steep it starts to
look like a wall....
</almost-on-topic>


I did a quick google search and came up with this mailing list thread:

http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg00499.html

It has the advantage of having a lot of people trying to explain it a
lot of ways, so hopefully one of them will start to make sense to you. :)

The explanation that has always worked for me is that a continuation
remembers a point in the execution of your program. As long as you are
holding onto that continuation you can, at any point (and as many times
as you like), jump back to exactly that place in your program again.
It's like a bookmark. You just replace your current execution context
with the one you copied for the continuation and carry on executing.

call/cc is a mechanism of getting/using the continuations which passed a
continuation into the method (or block, depending on implementation) you
ask it to call. The continuation it gives you is a capture of the point
in the execution just before the call/cc method call returns. So by
using that continuation, you can return from the method call over and
over as many times as you like.

We use this in seaside (and borges does the same) to allow the user to
use the back button in the browser. No matter how many times the user
goes back and clicks a link on the same page, the handling will always
be done by the exact same execution context. It doesn't know it's being
called over and over; it just knows it's supposed to handle the clicks
generated from that page and it always does.

Hope that helps,
 
J

Julian Fitzell

Carl said:
Is that always good? What if it means the users ends up clicking on the
purchase button twice and we charge their card twice? I've always
thought that it was best not to let the user use the back button in
cases like these (i.e., forward them to the right page, display an error
indicating that the posted values are stale, or something like that).

No, it's not always good. But it's always good to be able to. Seaside
(and I believe Borges for Ruby implements this piece too) has a concept
of transactions or isolate blocks. The way this works is that you
execute a section of code inside a block. When that block terminates,
all the pages in that session get expired. So in the case of a shopping
cart, you would likely start an isolate block when they begin the
payment process and expire all those pages as soon as they press "Purchase".

Note that you also have control over which pieces of state get
backtracked with the back button. So you can have the UI state
representing, for example, which tab is selected roll back with the back
button, but leave your model data (such as the shopping cart contents,
perhaps) so it always represents the newest data. It requires some
thought in each case to determine what the desired semantics are, but
once you decide what you want it's easy to implement either way.

Julian
 
C

Chad Fowler

<almost-on-topic>
I still can't get my head round continuations - does anyone have a good ref?

All I've seen so far is either 'look, we can do goto' or
'look, here's Borges', which is a learning curve so steep it starts to
look like a wall....
</almost-on-topic>

Not a tutorial or reference, but here's a stripped down
continuation-based web app that I wrote in order to demonstrate the
continuations "trick" from Seaside. It's stupidly simplistic, which
makes me think it might help you a little.

http://chadfowler.com/lazyseaside/pm_seaside.html

Ignore the wrap_methods and "hints" stuff. That's part of another
topic (http://chadfowler.com/index.cgi/Computing/Programming/Ruby/TypeWatching.rdoc,v)

Chad
 
K

Kaspar Schiess

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Carl Youngblood wrote:

| Is that always good? What if it means the users ends up clicking on the
| purchase button twice and we charge their card twice? I've always
| thought that it was best not to let the user use the back button in
| cases like these (i.e., forward them to the right page, display an error
| indicating that the posted values are stale, or something like that).

Well, this is actually a problem that has been given some thought. And
thus not a problem. In Borges, you would wrap the sequence of your
checkout steps with:

session.isolate do
show_checkout_step_1
show_checkout_step_2
# etc..
end

The effect of this is that you get a UI Transaction that protects your
checkout steps. Once the user enters the transaction, he can 'back' and
'forth' at will withhin the transaction. But once the final button for
checkout is hit, the transaction will be closed and the user can't go
back - all he gets is a redirection to the current page of the application.

I think that declaring the back button as forbidden is a bad idea,
rather make it work the way we expect it to !

There is also a

session.once do
show_some_unique_timedependent_info
show_some_other_stuff
end

that permits to step trough the sequence just *once*. You might want to
download and install Borges and run the following script on your machine
for happy testing of these features (and uh admire the nice
implementation we have ;) )

require 'Borges'
require 'Borges/Test'
require 'Borges/WEBrick'

Borges::WEBrickServlet.start

Then make a connection to localhost:7000/borges/test. I am talking about
~ the Once and the Transaction tab (whoa check out the tab control while
your at it).

The documentation at www.tua.ch/ruby is rather bad I fear; I will
hopefully get to write a full introduction that also explains the
concepts a bit more in depth.

- --
kaspar

semantics & semiotics
code manufacture

www.tua.ch/ruby
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAm/ScFifl4CA0ImQRAp1mAJ4lGlf8PCC/A59IMYJOL51Dk9jjCACeMc1O
B3unkr2dluf4Wm9J/Y1L/Mw=
=q09B
-----END PGP SIGNATURE-----
 
D

Dick Davies

* Kirk Haines said:
On Fri, 7 May 2004 19:58:29 +0900, Dick Davies wrote


Iowa doesn't use continuations.

Sorry, it's so closely tied up in my head with Borges I assumed it was
a similarly implemented framework.
I've finally gotten a start to the tutorial for it up:

http://enigo.com/projects/iowa

Cheers, I had the site bookmarked but I was waiting for a handhold..



Thanks for all the continuation links people have posted too, non-Smalltalkers
like myself appreciate it.
 
K

Kaspar Schiess

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

A couple of quick answers ;) :

Carl Youngblood wrote:

| Borges sounds pretty cool. Better documentation (including a good
| tutorial) would be a great help. A couple quick questions:
|
| - Can it work with mod_fastcgi/ruby?
I have a working version with mod_ruby. This is not in the CVS and will
stay around for another two weeks on my HD; I am definitily wanting to
do a fastcgi port. Current Integration methods are:

* mod_ruby (experimental)
* cgi
* webrick

| - Does the sessioning stuff support automatic fallback to GET-based
| session ID propagation if the user has disabled cookies?

You must use URL based session id's, there is no way around it. You can
optionally have cookies on top of that, but the urls really must be
there because of how Borges/Seaside is designed. And this probably does
not bother you anyway, since Borges should only be used for
Applications, not for Web Publishing.

| - Can sessions be stored in a database or a drb store so that web
| traffic can be easily load-balanced across multiple web servers?

One session should always use one server. This is because server state
is not saved, but kept alive in a Ruby process on the server. Ruby can't
currently dump what would be neccessary to dump to be able to save off
to a database (mainly continuations...).
Load balancing can balance sessions (users) to different backends, from
different frontends. But one session is always handled by one and the
same backend.

| - Is it necessary to construct HTML pages programatically or can you
| have simple unbroken HTML templates that are editable by a
| non-tech-savvy graphic designer?
I am using eruby to do my templating, so no trouble there. You just
need to take special care when constructing forms.

May I suggest that we take this discussion to the borges-users list ?
And could you sign here, here and here with your blood please ? ;)

Tell me if you need a better answer, I will keep a list of things to put
in the introduction based on this conversation.

kaspar

semantics & semiotics
code manufacture

www.tua.ch/ruby
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAm/6hFifl4CA0ImQRAlvsAKCVIt52qY/9uwxjQ6pF6OBUDm6E9wCdHfQ7
vH8UP49H7h2R5xl04cA+PsQ=
=OrNI
-----END PGP SIGNATURE-----
 
J

Julian Fitzell

Carl said:
Borges sounds pretty cool. Better documentation (including a good
tutorial) would be a great help. A couple quick questions:

My answers relate more to Seaside than to the ruby Borges, but since
Borges is essentially a direct port of Seaside as it was about a year
ago will probably still apply...
- Can it work with mod_fastcgi/ruby?
- Does the sessioning stuff support automatic fallback to GET-based
session ID propagation if the user has disabled cookies?

Seaside/Borges use GET parameters for session. Avi and I do not like
using cookies for session keys, not just because of the obvious problem
that some people disable cookies but also because it prevents the user
from having two windows open in two different sessions at the same time.

It wouldn't be hard at all to support cookie-based session keys
instead--just a simple matter of programming--but we have no desire to
have such a feature. We have had clients express interest, though, so
if it was something that somebody really wanted, we would probably
consider adding it (to seaside, that is).
- Can sessions be stored in a database or a drb store so that web
traffic can be easily load-balanced across multiple web servers?

There's nothing preventing you from writing your sessions out in some
way, but as Kaspar mentions, you need to be able to write out a lot of
contextual information including blocks for callbacks, etc. In Squeak,
you could do it with ImageSegments. I've thought of doing this
automatically whenever an error is encountered to make sure I can pull
the session up again later to see what was happening.

But, as he also mentions, the best thing to do for load balancing is to
ensure session affinity. Most load balancers will allow you to do this.
you just let new requests with no session key go to any server and any
request that does have a session key needs to get sent to the same
server from then on.
- Is it necessary to construct HTML pages programatically or can you
have simple unbroken HTML templates that are editable by a
non-tech-savvy graphic designer?

No, it's not necessary. We moved away from using templates because it
became impossible to factor them as well as we'd like. By generating
the html programmatically we can break it up into methods, reuse pieces,
parameterize them, etc. With CSS increasing in popularity, the model we
advocate is that the visual designers do the CSS and the developers
generate bare-bones HTML with lots of CSS ids and classes. Obviously
the two need to work somewhat iteratively to move stuff around as needed.

Have a look at www.csszengarden.com for inspiration if you haven't yet
discovered the power of CSS.

Cheers,

Julian
 
K

Kirk Haines

On Sat, 8 May 2004 05:33:02 +0900, Julian Fitzell wrote
Seaside
(and I believe Borges for Ruby implements this piece too) has a
concept of transactions or isolate blocks. The way this works is
that you execute a section of code inside a block. When that block
terminates, all the pages in that session get expired. So in the
case of a shopping cart, you would likely start an isolate block
when they begin the payment process and expire all those pages as
soon as they press "Purchase".

Now THAT is a cool idea. I need to think about how to steal that and
implement it in Iowa to selectively expire pages from the page cache. That
would be a useful capability.


Kirk Haines
 
K

Kirk Haines

On Sat, 8 May 2004 05:56:09 +0900, Dick Davies wrote
Cheers, I had the site bookmarked but I was waiting for a handhold..

Drop me an email if you have any questions. More is going up later this
evening.


Thanks,

Kirk Haines
 
K

Kirk Haines

On Sat, 8 May 2004 05:56:09 +0900, Dick Davies wrote
Sorry, it's so closely tied up in my head with Borges I assumed it
was a similarly implemented framework.

I thought I'd run down a quick list of Iowa/Borges differences.

* Iowa operates on a traditional request/response paradigm and represents
everything as an object, using objects to track state; Borges uses
continuations to maintain the user's path through the application.

* Seaside (and thus, Borges, too) has some fancy neat stuff in it that I
would like to implement in Iowa, like the notion of isolating a section of
the application so that when the user exits that section, the past pages are
expired. Seaside/Borges definitely has some advanced features that Iowa
does not have.

* Borges is targetted very specifically at web applications. Iowa was also
targetted specifically at web applications, but I have built a layer that
allows one to map URLs to specific components to handle them, allowing Iowa
to be used as a general engine for dynamic web content and allowing more
flexibility about how entry points into an application are mapped to URLs.

* Borges and Iowa both run as discrete backend processes from the webserver.

* Iowa uses a template type architecture using plain HTML. Borges generates
the HTML programatically using an API to describe the content and a renderer
to take that description and turn it into appropriate content (which means
that the same Borges application could, in theory, generate HTML or run from
command line or generate a Fox GUI).

* Iowa has full access to the HTTP headers that are received and that are to
be sent back to the browser, making it easy to use cookies, set content
types, and that sort of thing, where needed. I don't know about
Borges/Seaside on this one?

* They are both pretty neat, even though they really have more differences
than similarities. Borges definitely pushes the innovation envelope more
than Iowa does. Iowa is more conventional.


There are a lot of other things that are different about them, despite a few
superficial similarities, but that should paint a good general picture, I
think.


Kirk Haines
 
K

Kirk Haines

On Sat, 8 May 2004 09:16:49 +0900, Carl Youngblood wrote
You are probably aware of this, but putting session IDs in URLs can
make it easier to hijack sessions. Here is a good article that
explains some of the things to consider when designing a session
manager (it's for PHP but the principles are universal):
http://www.sitepoint.com/blog-post-view.php?id=156260&ct=1

Particularly, it is important to make sure that any external links
don't get the session appended to them, or other internet servers
will see them.

Iowa and Seaside/Borges both handle this in basically the same way.

Application URLs look something like this (for Iowa):

http://somehost.com/guestbook/11131dab-105c6c68-abNmbFaYA5gFE.a.1.7

The random looking gobbledeygook at the end is the session id. It is unique
over a pretty large space of possible ids, so should be hard to guess. A
similar sort of thing holds true for Borges/Seaside.

These application URLs get generated by the framework automatically, and
right now I can't even think of a way to get that session ID tacked onto a
URL that points to someplace outside of the application.

One of my reasons for planning on adding a mechanism to store this id in a
cookie, though, is because it is pretty ugly. There are cases where I would
prefer to not have that stuff showing up on the URL line in the browser and
where using a cookie for it would not be a problem.
The advantage of using another backend for sessioning is that a
webserver can fail or be rebooted/replaced without any users being
affected by it. They will transparently be sent to a different
webserver by the hardware load balancer and their session will
remain intact.

Yep. And that would be a cool feature. For Borges, though, I think this
would be pretty difficult because it is continuation based. To truly
serialize and reconstruct the session seems to me like it would be quite a
difficult and impressive task.

For Iowa the bar isn't quite so high since sessions and the page trail for
each session are all objects. It's probably possible to do it for Iowa
without too much overt difficulty. However, it still seems like it would be
a pretty expensive task in terms of processing and time usage, and for most
things, most of the time, probably isn't worth it. It's something that I
have been thinking about off and on for probably two years but it's just
never been something that I needed enough to spend the time on it.


Kirk Haines
 
J

Julian Fitzell

Kirk said:
* Iowa uses a template type architecture using plain HTML. Borges generates
the HTML programatically using an API to describe the content and a renderer
to take that description and turn it into appropriate content (which means
that the same Borges application could, in theory, generate HTML or run from
command line or generate a Fox GUI).

This is only because we haven't implemented a templating layer in
Seaside. There is a templeting system called Nori written by Colin
Putney for Seaside, so it can be done.
* Iowa has full access to the HTTP headers that are received and that are to
be sent back to the browser, making it easy to use cookies, set content
types, and that sort of thing, where needed. I don't know about
Borges/Seaside on this one?

Seaside does as well. We don't pass the server's request object in
directly because we want an abstraction there, but we do have a request
object that is accessible.
* They are both pretty neat, even though they really have more differences
than similarities. Borges definitely pushes the innovation envelope more
than Iowa does. Iowa is more conventional.

I don't know about conventional. But Seaside *is* the successor to
Iowa, so it's hardly surprising that Seaside pushes the envelope more.
 
J

Jamis Buck

Carl said:
I personally don't see a big need for running
multiple sessions simultaneously, but I can see why someone might want
to do it. I prefer to use cookies for sessioning and have the web app
automatically fall back to GET propagation if the user has cookies
disabled.

It's not even the need to support multiple sessions that make using
cookies for session management evil. I work as a programmer at BYU, and
we have been putting all of our applications (student registration,
grade submission, class scheduling, etc, etc) all online for several
years. (Not using Ruby, alas, but I'm making some inroads to increasing
Ruby's acceptance here... that's another story, though...)

Two big problems we had when using cookies for session management:

One. Picture two students, roommates, with one computer between them.
Student "A" logs into the online registration app and registers for a
few classes, and then minimizes the browser window without logging out.
Shortly thereafter, Student "B" comes along, opens a new browser window
(not realizing that there is already a window open, but minimized) and
logs into the online registration app. He then registers for a few
classes, and closes his window (without logging out). Student "A"
returns, and restores his browser window, intending to add a few more
classes. AT THIS POINT, THE SESSION REFLECTS THE ACTIVITY OF STUDENT B,
NOT STUDENT A. When Student A adds a class, he inadvertantly adds it to
Student B's schedule, which may not actually be realized until the
semester starts. This problem actually bit us hard a few years ago.

Two. Picture an administrative employee. They are editing a student's
grade history when they get a phone call. It is another student with a
question about their grades, so the employee (not wishing to lose their
place) opens a new window and uses it to answer the student's question.
Then, they close that new window to return to their place. THE SESSION
NOW REFLECTS THE CALLER'S IDENTITY, NOT THE ORIGINAL STUDENT'S IDENTITY.
Thus, when the employee changes a grade, it goes to the caller's record,
not the original student's! This also bit us hard a few years ago.

We got around this by using what we have called a "brownie." It is the
encoded and encrypted session information, stored in a hidden field on
the page itself and propogated via POSTs. (Another problem with using
GET, in addition to what I've read in this thread, is that GETs are
technically limited to 1k of data, which--in our case--is often
insufficient to transmit the brownie.)

This solution has served us well, though imperfectly. It required quite
a bit of infrastructure code to be written to support, which has
resulted in some maintenance and training headaches, but such is the
nature of web development, I guess.

--
Jamis Buck
(e-mail address removed)
http://www.jamisbuck.org/jamis

ruby -h | ruby -e
'a=[];readlines.join.scan(/-(.)\[e|Kk(\S*)|le.l(..)e|#!(\S*)/) {|r| a <<
r.compact.first };puts "\n>#{a.join(%q/ /)}<\n\n"'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,371
Latest member
Brkaa

Latest Threads

Top