Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

developing a maintainable RPC system

I am working on a web application that will make extensive use of AJAX techniques for client/server communication...JSON-RPC specifically. Zend Framework is being used server-side, and it offers a nice JSON-RPC server that I would like to use.

My goal is to architect a maintainable system that exposes a large subset of server-side functionality to the client-side (javascript), without unnecessary code duplication. I've seen numerous blog posts and tutorials on how to use ZF's JSON-RPC server (see here and here), but they all seemed geared towards exposing a small, publicly consumable API. Code duplication is common, for example one blog post has the following method exposed:

public static function setTitle($bookId, $title) {
    $book = new Nickel_Model_Book($bookId);
    $book->setTitle($title);
    $book->update();
    return true;
}

I don't like the fact that there are two setTitle methods. If the method signature for one changes, the other has to be kept in sync...seems like a maintainability nightmare if your API is extensive. It seems to me that there should be one Book class, with one setTitle method.

My initial thought is add a docblock annotation @export to methods/classes that I want exposed. When I decide to expose the setTitle method, I just add the annotation rather than a new method.

One potential problem I see involves object persistence. Server-side, it makes sense for setTitle to set the object's title property...but not persist it in the database until update() is called. Client-side, calling setTitle should immediately affect the database. One potential solution is to modify all accessors such that they take a optional second parameter signifying the modification should update the database immediately:

function setTitle($title, $persist = false) {
    $this->title = $title;

    if ($persist) $this->update();
}

Some sort of proxy class could ensure that the $persist flag is set for all client-side RPC invocations.

Another problem is the serialization of PHP objects. Server-side, it makes sense to do a OO-style $book->setTitle("foo") call, but client-side book.setTitle(1234, "foo") makes sense (where 1234 is the book's ID) due to the lack of state. My solution for this would be to have the aforementioned proxy class be responsible for somehow turning book.setTitle(1234, "foo") into:

$book = new Book();
$book->load(1234);
return $book->setTitle($title);

I feel like this problem must have been tackled or discussed before...but I'm not finding many resources online. Does this seem like a sane solution?

like image 367
Josh Avatar asked Nov 22 '10 18:11

Josh


2 Answers

What you're looking for is called Service Layer.

Their entities should be purely data containers (unless you're using Active Record), you should only expose your service layer, and this in turn accesses their entities and their respective methods.

"Your Book class is a Domain Model, you should now create your Service Layer"

Your class of service would be something like this:

class BookService extends Service {

    //...

    public function changeBookTitle( $title, Book $book )
    {
        //verify if the $title is correct and valid
        $book->setTitle( $title );
        $this->methodToGetThePersistenceManager()->save( $book );

        //fire events, create a result object, etc...
    }
}
like image 109
jonathancardoso Avatar answered Sep 26 '22 03:09

jonathancardoso


I was mulling over your question for a few minutes. If you want to try, and it's in PHP, you could make some magic methods of the form

set{Property}of{Object}.

You can do this through the magic __call method.

That way you wouldn't have to explicitly define the methods but the properties would still get set.

The magic method would identify which type of object it has to instantiate and which property to set on it and then persist.

You'd have to find some way of differentiating between remote calls and local calls though so you don't persist by mistake if you're making local library calls and that you do persist on remote calls.

I feel like I misunderstood your question somehow but I tried.

like image 42
Jerry Saravia Avatar answered Sep 24 '22 03:09

Jerry Saravia