[cl-openid-devel] message object (was: cl-openid: API design, code finalization and nearest future plans)
Anton Vodonosov
avodonosov at yandex.ru
Thu Jul 31 00:02:07 UTC 2008
on Wednesday, July 30, 2008, 2:03:04 PM Maciek wrote:
> As I wrote in yesterday's report, there's one more thing I decided to
> change. I'd wish to turn from alists representing messages to
> OPENID-MESSAGE structure (it’s just a struct, since there’s no need
> for OOP here). The structure would be a thin layer atop parameter
> alist, plus accessors. This may make the code cleaner by use of
> clearly named accessors instead of sprinkling code with AGETs. Also,
> commonly used lookups (such as namespace check to determine protocol
> version) can be moved to struct fields, which would make many alist
> lookups unnecessary.
> This is actually not a major change, but one I see really useful for
> cleaning up the code.
...
>> Please provide your comments. In your blog you mentioned some MESSAGE
>> object and I have impression that you are planing more complex
>> refractoring.
> Not really. The OpenID protocol is concentrated on exchanging
> messages. The messages take different forms, external encodings and
> transmission channels, but they’re essentially same thing all over.
> Protocol draws a distinct line between logic (behaviour) and data
> (message encoding, decoding, handling).
> In current code, it is not so. The message handling code is mixed
> with logic, and done with general functions. What I want to do is to
> separate message-handling code to its own file, with clearly named
> functions and accessors.
> Consider the fragment from auth-request.lisp:
> ,----
> | (let ((response (direct-request (aget :op-endpoint-url id)
> | (acons "openid.mode" "check_authentication"
> | (remove "openid.mode" parameters
> | :key #'car
> | :test #'string=)))))
> | …)
> `----
> Protocol logic is mixed with low-level message mangling. I want it to
> look more like this:
> ,----
> | (let ((response (direct-request (endpoint-url auth-process)
> | (copy-message response
> | :mode "check_authentication"))))
> | …)
> `----
> This should also improve testability – it should be easy to write
> tests for internal message API, and it would ensure there are no
> alist-mangling-level bugs in the conversation implementation, so only
> the behaviour would need to be tested there.
OpenID messages are key-value lists, so alists are close enough...
Of course we should not sprinkle the code with AGETs, but you can defun
clearly named accessors operating directly on alists, without introducing
a MESSAGE struct:
(defun get-field (msg key)
(aget key msg))
(defun copy-msg (msg alist-to-add)
(append alist-to-add (remove-if (lambda (key)
(member key alist-to-add
:key #'car
:test #'string=))
msg
:key #'car)))
(copy-msg response '(("mode" . "check_authentication")))
(The functions have not been tested)
Defining copy-msg to accept parameters as in your example
is not a problem too.
As for caching namespace check and other lookups into the MESSAGE
struct fields, it is unnecessary - alists in questing are short and
lookups are very cheap; also, in many cases namespace check
is performed only one, maybe two times during message lifetime,
so you will not save any performance (to be precise, you may even
lose it - parsing server parameters into message struct has some cost
too).
In sort, considering performance questions here is an exactly
"preliminary optimization".
As I see Python's open-id message class deals with some namespaces
for parameters, but this is for extensions as I understand and
we do not need it now.
I will try to think more about the messages tomorrow too.
Best regards,
-Anton
More information about the cl-openid-devel
mailing list