On Thu, Mar 11, 2010 at 4:59 AM, John Patterson <jdpatter...@gmail.com> wrote:
>
> Well then, where are your examples?  I responded to the "edge cases" you
> asked about with a simple example.  Now its your turn to show me how
> Objectify would code the example I asked about.

I can see you are proud of your OR implementation.

I'm not going to respond to a feature by feature comparison; clearly
Twig has more features than Objectify, and while you're still missing
several critical features necessary to build real-world applications
today (2nd level caching, schema migration tools, batch gets) I'm sure
you will eventually add them.

I'm still pretty comfortable making my claim that in a Real World
application (not contrived examples designed to highlight Twig's
features), the corresponding code in Objectify will be more elegant.
Despite your ranting about the evils of Key, I (and quite a few
others) have developed sophisticated applications with Objectify and
we like the result.

I'll grant you that some of what are annotations in Twig might result
in code in Objectify.  This isn't necessarily a bad thing.  Taken to
an extreme, JDO has created an annotation for nearly everything,
producing a nasty initial learning curve.  I'm of the opinion that
annotations are code just like anything else, so I think it's fair to
let the user type a little more when they are running a query - as
long as the code reads well.

I submit, as my code examples, the documentation for Objectify:

http://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify

There's plenty of code there, all of which demonstrates actions that
you need to do in the real world.

However, I don't expect to convince you of anything.  You seem to
believe that your API is so magnificent that it doesn't require
Javadocs, and that Objectify's iterable query is some sort of bug
magnet.  This makes me question your sanity.

If you want to create a Real World application for comparison, I might
be willing to spend a little time creating an Objectify version.
Otherwise, I suggest that any readers actually go through the docs for
both projects and see which one you like better.

> You are still mixing the concepts of data model portability and data access
> layer (DAOs) portability.

Even if you have Key<?>s in your entities, it doesn't mean you have to
use them outside your DAO layer.  This is up to the app architect.

But it is pointless for me to argue this point; clearly having managed
object graphs can *help* with portability.  It's a grey continuum.
And if you are deeply concerned about this kind of portability, today,
you should be using JPA or JDO.  Maybe you'll end up having a Key here
and there that you must replace, but you won't end up rewriting your
entire DAO layer.

>> The only data access API that gives you any hope (tenuous as it is) of
>> real portability is JDO/JPA.
>
> Are you having a laugh?  After all your rants about how portability with
> JDO-GAE is impossible... that is really grasping at straws.
> I claim that Twig data models are more portable that JDO-GAE, JPA and
> Objectify data models.  Why?  Because they are pure POJOs with no low level
> datastore dependencies - simple.

Actually, I'm quite serious.  I rant against the wild claims and
religious zeal that the JDO guys express on this list, a religion that
you seem to have become infected with.

Neither JDO nor Twig (and certainly not Objectify) produce portable
applications.  But certainly application portability (the only kind
that matters) is a grey spectrum and some frameworks make it easier
than others.  Furthermore some applications are easier to port than
others.

In fact, if you want *real portability*, the best thing to do is to
create stripped-down entities that work like this:

class Employee {
    @Id Long id;
    Long managerId;
}

class MyDAO {
    public List<Employee> getSubordinates(Long managerId) { ... }
}

This actually has a hope of being ported to another system (SQL or
NoSQL) relatively intact.  Twig's use of data structures with "hollow"
entities can be convenient but it does not have a corollary on other
systems, and will not necessarily make your application easier to
port.  It really does depend on the application.

Which is why I don't like to get into abstract arguments.  Make a real
world app, and I will care.  We can even port it to a (real) JPA
system for fun.

>> In my development with Objectify, I haven't found it necessary to use
>> Key objects in the higher levels of my app - just at the level of
>> DAOs.  However, I do use GeoPt a lot.  There are a lot of things that
>> might change if I had to port away from GAE, and this is just one of
>> them.
>
> Obviously a rather large one.

It would not be difficult to replace GeoPt with my own equivalent
GeoPt class.  I probably wouldn't have to do anything but change the
imports in a global search & replace.  Yawn.

> In a system such as GAE which makes so much so hard productivity features
> are a great relief. No OR queries?  Of course I value simplicity - but the
> whole idea of a framework is to push complexity from the user code into the
> framework.  Objectify leaves too much too the developer for my liking.  It
> is simple - I grant you that - but that makes app code more complex.

It certainly can.  And if you need to do a lot of OR queries that
can't be easily wrapped in a neat utility method (after all, it's
usually just run two queries and union the results), I'll be the first
person to direct users to Twig.

On the other hand, a simple re-usable utility method is typically not that hard.

>> I don't like the idea of entities that look like User #1234 but don't
>> have the data of User #1234.  This feels like it has a lot of bug
>> potential to me.
>
> All referenced objects are activated by default - the developer actually has
> to explicitly choose to use this feature as an optimisation so there are no
> surprises.

Objects frequently get loaded and then passed through several function
calls to code that doesn't know the state of the object and might be
maintained by a different engineer.  As someone that thinks
Query.iterator() is errorprone but stateful entities are safe, you
seem to have an odd sense of danger.

I'm not suggesting this is a bad feature, but it has its risks.
You're using an uninitialized POJO to do what JDO/JPA use a proxy for.
 At least proxies have the advantage that they tend to work correctly
most of the time and they provide clear error messages when they
don't.

Gavin once told me that the #1 most common issue people have with
Hibernate is "Why do I get this LazyInitializationException?"  In your
system, every one of those errors is going to be an unintended
reference to an uninitialized entity - possibly undetected, returning
bad data.

Say what you will about Key objects, at least they always work.

> Managing object identity is a lot more than just keeping an Id field.  It is
> a guarantee that if you load the same instance twice from the datastore they
> will be identical instances.  obj1 == obj2
> Objectify has no such guarantee so you could end up loading two referenced
> instances with the same id, making changes and puting them again only for
> one to overwrite the other.

Yep.  Objectify entities are plain, boring POJOs that work just like
every other Java object.  You can load them, clone them, save them,
serialize them in and out, whatever.  There is no magic.

> The Objectify framework has the advantage of simplicity because it has fewer
> features.  The Objectify user code is more complex because the user must do
> more "manually".  The merged OR query is just one example of this.
> In my opinion the goal for any GAE framework should be to help overcome the
> great and unusual limitations of the environment.  To encapsulate solutions
> in one place to avoid repeating them again and again.

We evaluate real-world pain points based on our own and our user's
experiences, then add features to solve those pain points as elegantly
as possible.  OR queries haven't been a pain point.  Maybe they will
be in the future, in which case we'll consider adding the feature.  We
are content to wait for the request.

>> Without dirty detection, aren't you likely to persist quite a large
>> object graph every time you do a put?
>
> No.  Updating or storing an item makes all reachable items persistent _only_
> if it is not already persistent.  Each item that changes must have update
> called.

So saves cascade if the entities are new, but not if the entities were loaded?

By the way, how do you distinguish between these three types of relationships:

class One {
    @Id Long id;
}
class Many {
    @Id Long id;
    @Parent Key<One> one;
}

vs:

class One {
    @Id Long id;
}
class Many {
    @Id Long id;
    Key<One> one;
}

vs:

class One {
    @Id Long id;
    List<Many> many;
}
class Many {
    @Id Long id;
}

> Twig is already much more capable than JPA on GAE for a very good reason:
>  It is designed specifically to work with GAE.  Integrating performance
> features like "Parallel Asynchronous Commands" into JPA or JDO would be
> impossible.

JPA/JDO is getting support for joins.  Are you planning to add this?

I'll grant you that async queries are nice.  I like it enough that
it's a potential future feature for Objectify.

> I can honestly say that without Twig my app would be at least 100 times
> slower.  Why?  Embedded collections have probably reduced the multiple
> queries required in JDO by 10 fold.  Parallel queries have now reduced the
> query another 10 fold.

I wouldn't be so certain that it's impossible to add embedded
collections to the DN plugin as an extension.  Not that I expect it to
happen anytime soon.

(for those keeping score, Objectify supports embedded collections)

> Reducing key strokes is a much lower priority in Twig than creating
> readable, maintainable code.
> It seems that method naming in Objectify takes the oposite approach.

You should really give it up.  Or talk to a third party about which
Query interface is easier to use and understand.

> Hey, I just noticed something.  Does Twig lack simple batch get()
> operations?
>
> I frequently write code like this:
>
> Set<Long> ids = ... // fetch user's friend ids
> Collection<Person> friends = ofy.get(Person.class, ids).values();
>
> What is the Twig equivalent?
>
> This would be handled with a simple direct collection reference in Twig like
> this:
> user.friends

Why do you assume that the friends came from some sort of internal
datastore object?  In my case, the friend ids come from Facebook.  If
you work with data from third parties, you will frequently load
objects with ids that are not of your own making and that have
relationships that are not defined in your data structures.

Batch gets are essential.

> So the batch get by key is really not so useful in Twig - or at least I
> haven't had the need for it yet.
>  But I can see cases where would be useful
> and am planning on adding a fluent load (and delete) commands which - just
> like the find and store commands - has "advanced" features such as
> returnResultsLater() and bulk load.
> I just noticed, how do you set the chunk size in Objectify?  I can't see the
> option anywhere.
>
> In Twig it is getResultsBy(50)

It's a minor implementation detail that nobody has asked for or cared
about yet.  But if they did, it would probably be Query.chunkSize().

Jeff

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to