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.