Return to Video

WebObjects Quite Good Practices

  • 0:00 - 0:02
    OK, welcome to the best practices session.
  • 0:02 - 0:03
    I'm Chuck Hill
  • 0:03 - 0:06
    I work for Global Village Consulting.
  • 0:06 - 0:09
    It's a WebObjects consulting house based out of Vancouver, Canada
  • 0:09 - 0:11
    I'm fairly active on the mailing list
  • 0:11 - 0:14
    so many of you will probably know my name.
  • 0:14 - 0:17
    You may have heard it once or twice before.
  • 0:17 - 0:20
    I'm also the coauthor of Practical WebObjects.
  • 0:20 - 0:23
    If you don't have a copy of the book, you probably want one.
  • 0:23 - 0:26
    Thank you, thank you, thank you.
  • 0:27 - 0:31
    OK, so this started out being called WebObjects Best Practices Sessions,
  • 0:31 - 0:36
    but as I looked at them and I talked to some of the other illustrious experts
  • 0:36 - 0:41
    it became obvious that we didn't all agree on exactly what the best practice was.
  • 0:42 - 0:47
    I decided to waffle a little bit, and it's Quite Good Practices.
  • 0:50 - 0:51
    My intention as going through here
  • 0:51 - 0:53
    is I'll present some best practices
  • 0:53 - 0:55
    and I'll give some members of the panel here
  • 0:55 - 0:58
    the opportunity to heckle me
  • 0:58 - 1:02
    and tell me that my best practices aren't really very good at all
  • 1:02 - 1:06
    and give you some ideas of theirs and what might be better.
  • 1:06 - 1:09
    In fact, some members of the panel
  • 1:09 - 1:12
    may argue that there is only a single best practice
  • 1:12 - 1:14
    which is use Project Wonder.
  • 1:19 - 1:20
    I won't tell you that.
  • 1:20 - 1:23
    I'm not going to assume you're going to be using Project Wonder
  • 1:23 - 1:29
    but I'll mention a few really cool things that are Project Wonder that you probably want to use.
  • 1:29 - 1:33
    Keep in mind also that this is a what session
  • 1:33 - 1:35
    it's not a how session.
  • 1:35 - 1:37
    I'm not going to tell you how to implement all of these things.
  • 1:37 - 1:40
    There's the wiki, there's the mailing list.
  • 1:40 - 1:43
    There are lots of ways to figure out how to implement this.
  • 1:44 - 1:49
    At the end hopefully we'll have some time for some questions and answers.
  • 1:49 - 1:51
    Some topic areas.
  • 1:54 - 1:58
    The first topic area, I divided it up into four areas, is going to be WebObjects.
  • 1:58 - 2:01
    What we're going to focus on here is the presentation layer
  • 2:01 - 2:05
    not the whole WebObjects framework but just components
  • 2:05 - 2:09
    talking about getting things out to a viewer.
  • 2:09 - 2:11
    The next thing is EOF,
  • 2:11 - 2:13
    so we're going to look at some enterprise object‑related,
  • 2:13 - 2:17
    database‑related things that are best practices.
  • 2:17 - 2:21
    There's just a few things that are pretty much generically Java
  • 2:21 - 2:24
    but they have a particular application to WebObjects,
  • 2:24 - 2:26
    so we'll cover those in Java.
  • 2:26 - 2:31
    We'll finish up with a few deployment best practices.
  • 2:34 - 2:38
    The whole point of having best practices
  • 2:38 - 2:40
    is so that your application doesn't end up
  • 2:40 - 2:44
    looking like what these two gentlemen are standing on.
  • 2:44 - 2:45
    I have, over the years,
  • 2:45 - 2:49
    maybe written some applications like this a long time ago.
  • 2:49 - 2:51
    I've inherited a few of them.
  • 2:51 - 2:53
    Trust me, you don't want one.
  • 2:55 - 2:59
    OK. On to our WebObjects presentation layer of things.
  • 3:02 - 3:04
    We're going to talk a little bit about page inheritance.
  • 3:04 - 3:06
    Now, WebObjects is pretty good,
  • 3:06 - 3:11
    and you can use it out of the box and you can get a lot of value out of it.
  • 3:11 - 3:12
    That's what people usually start doing...
  • 3:12 - 3:17
    everything is WOComponent and then my page.
  • 3:17 - 3:21
    Judging by all the people who've written frameworks,
  • 3:21 - 3:25
    you're probably going to find out pretty soon that you've got a lot of common code all of your pages
  • 3:25 - 3:30
    One of the things that you should do is create a common page.
  • 3:30 - 3:32
    Now, this is just a Java class.
  • 3:32 - 3:35
    There's no WO file. There's no template involved in it.
  • 3:35 - 3:41
    It's just common Java things, takes the good stuff that comes from WebObject's WOComponent
  • 3:41 - 3:43
    and adds some more good things to it.
  • 3:43 - 3:48
    Then, search results here, as an example of a page you might write,
  • 3:48 - 3:50
    which inherits from common page.
  • 3:50 - 3:56
    It's a way of getting a lot of benefit on your pages without having duplicated code all over the place.
  • 3:56 - 4:02
    Let's take a quick look at some of the things you might want to do in this common class.
  • 4:02 - 4:06
    Enhance WebObjects with editing context,
  • 4:06 - 4:09
    this is something important, and we're going to keep coming back to this again and again
  • 4:09 - 4:14
    If you're writing your pages using "session.default" editing context,
  • 4:14 - 4:17
    you're not using abstraction correctly.
  • 4:17 - 4:20
    You're programming to an implementation of something.
  • 4:20 - 4:22
    Sooner or later, you're going to want to change that,
  • 4:22 - 4:25
    and you're going to have a lot of code in a lot of places.
  • 4:25 - 4:28
    Putting something like that on your page
  • 4:28 - 4:32
    and having everything deal with that allows you to change it a lot more easy.
  • 4:32 - 4:35
    You'll see that it'll make your pages a lot more flexible.
  • 4:35 - 4:38
    Binding support, WebObjects has pretty good binding support.
  • 4:38 - 4:41
    Does it have a binding? Give me the value for the binding.
  • 4:41 - 4:44
    You can do a lot of useful things, though.
  • 4:44 - 4:46
    Casting bindings, give me the string value for the binding.
  • 4:46 - 4:48
    Give me a Boolean binding.
  • 4:48 - 4:51
    Give me this Boolean binding with a default of True.
  • 4:56 - 4:57
    Access control,
  • 4:57 - 5:02
    most of the apps you're going to end up writing are probably not going to be completely public
  • 5:02 - 5:06
    like the Twitter example where anybody can see anything and we don't really care.
  • 5:06 - 5:10
    By putting the access control in the page superclass,
  • 5:10 - 5:13
    you make sure that it's handled consistently all across the application.
  • 5:13 - 5:16
    You don't have to remember, "Oh, I've got to do it in this page.
  • 5:16 - 5:17
    Oh, I have to do it in this page.
  • 5:17 - 5:21
    You do it once, and it's handled consistently across.
  • 5:21 - 5:24
    KVC extensions, I like to play with KBC extensions.
  • 5:24 - 5:28
    You can do a lot of interesting things overriding key‑value coding
  • 5:28 - 5:30
    besides what it normally does.
  • 5:30 - 5:35
    One of the things that I've done recently is to make bindings like this.
  • 5:35 - 5:42
    When the page sees that, it takes it around and it ends up calling a session method.
  • 5:42 - 5:46
    With [indecipherable] in the session, can the current user...?
  • 5:46 - 5:49
    Do they have Create Users permission or not?
  • 5:49 - 5:54
    It ties the bindings directly into the authorization system.
  • 5:54 - 5:56
    You don't actually need the "@" in front.
  • 5:56 - 5:59
    You could just use Can User, but when I do extensions,
  • 5:59 - 6:02
    I usually put a little character in there to remind people that,
  • 6:02 - 6:04
    "Hey, this one's special."
  • 6:06 - 6:11
    The best way to learn things to do in this is to look at what other people have done.
  • 6:11 - 6:15
    ERX component, which Mike mentioned, was just added this year to Wonder.
  • 6:15 - 6:19
    It's a great source of ideas for the things that you can do in your own class.
  • 6:19 - 6:22
    As I think, Andrew has a component in his class.
  • 6:22 - 6:29
    Pierre has some in the How to Frameworks. Lots of good examples out there.
  • 6:29 - 6:31
    Yeah. I wasn't going to pump my own self, though.
  • 6:31 - 6:34
    I'm trying to let those go away.
  • 6:34 - 6:37
    There are lots of good examples out there. Take a look, get inspired.
  • 6:38 - 6:39
    Any comments from the peanut gallery?
  • 6:40 - 6:42
    - Yes.
    - Yes?
  • 6:42 - 6:47
    Access control is something I forgot to mention. It will probably also come to your attention.
  • 6:47 - 6:49
    - OK.
  • 6:49 - 6:51
    - That's all.
    - With a cool KVC extension?
  • 6:51 - 6:56
    - Yes, actually.
    - Just one thing on the KVC extension.
  • 6:56 - 7:00
    If you're running you try to have a look at the name space.
  • 7:00 - 7:08
    There's a very, very cool feature in the [indecipherable] where we extend the binding property.
  • 7:08 - 7:14
    Actually you are [indecipherable].
  • 7:15 - 7:18
    Have a look at the name space and the binding.
  • 7:18 - 7:21
    It's a really, really cool feature.
  • 7:21 - 7:27
    OK. Now next thing I want to look at is component inheritance.
  • 7:27 - 7:29
    Basically taking the same idea we had before,
  • 7:29 - 7:33
    little component, we have a common page and a common class in a search results,
  • 7:33 - 7:36
    and saying "Well, OK, here's what the page does
  • 7:36 - 7:40
    but for components that appear in the page we want to make things a little bit different."
  • 7:40 - 7:44
    I've introduced the idea of a common component class, just pick the name.
  • 7:44 - 7:48
    As an example a result list is going to be a component that you would use in a page.
  • 7:48 - 7:52
    For example, the result list on the search results page.
  • 7:53 - 7:55
    Why do this?
  • 7:57 - 8:01
    Validation handling is one.
    Who is it now?
  • 8:01 - 8:05
    I think Andrew's thing was showing how the components...
  • 8:06 - 8:11
    what's the word I'm looking for? Cooperated with the page, passing the validation messages around.
  • 8:11 - 8:14
    Instead of having one big block at the top that said
  • 8:14 - 8:17
    "You hit saved changes and this bad stuff happened"
  • 8:17 - 8:21
    you can have the error appear beside each component where it applies.
  • 8:22 - 8:25
    This is an important one.
  • 8:25 - 8:29
    Going back before we said each page should have the concept of an editing context,
  • 8:29 - 8:33
    each component shouldn't have the concept of an editing context.
  • 8:33 - 8:37
    Each component should use the page's editing context.
  • 8:37 - 8:41
    If you ever change the page's editing context,
  • 8:41 - 8:43
    that flows all the way down through the page.
  • 8:43 - 8:46
    If you have "session.default" editing context buried everywhere,
  • 8:46 - 8:49
    you've got a lot of changes to make.
  • 8:51 - 8:56
    That's a very simple way of how you do it, just put that in there.
  • 8:56 - 8:59
    Get the context page, it will give you whatever the top level page is.
  • 9:00 - 9:02
    Cast it to your generic class,
  • 9:02 - 9:05
    and that's what you should be using for an editing context.
  • 9:08 - 9:10
    - Interesting.
    - You don't do that?
  • 9:10 - 9:13
    - I don't do that right now.
    - Oh my...
  • 9:16 - 9:22
    - You learned something today.
    -I learned something. Thank you [indecipherable]
  • 9:22 - 9:24
    - Yes?
  • 9:29 - 9:33
    - Hello? That's a great idea, Chuck.
  • 9:33 - 9:36
    I'm going to start doing that.
  • 9:41 - 9:46
    OK, and taking the whole idea one more step further, and this one's pretty simple.
  • 9:47 - 9:52
    The stuff up above the common component, that's pretty generic code.
  • 9:52 - 9:57
    But the problem with Java is in the WebObjects framework
  • 9:57 - 10:04
    the component method's application and session are cast to return a WO session and WO application.
  • 10:04 - 10:07
    Now usually you've extended them. You've got some of your own stuff in them,
  • 10:07 - 10:10
    so all through your pages you end up casting it and casting it.
  • 10:12 - 10:16
    They usually include a couple pages like that in the application
  • 10:16 - 10:20
    just strictly for the point of casting convenience.
  • 10:23 - 10:26
    That's not going the way it's supposed to.
    Like that.
  • 10:26 - 10:30
    The whole point is override the method and cast it like that.
  • 10:30 - 10:33
    You can only do this with Java 1.5.
  • 10:33 - 10:36
    If you're still using Java 1.4, the compiler will whine at you.
  • 10:36 - 10:40
    You have to make a method with a different name like "the session."
  • 10:43 - 10:46
    Same idea for the application.
  • 10:49 - 10:51
    Any fun generic stuff Mike?
    No?
  • 10:52 - 10:54
    Also great.
  • 10:56 - 10:57
    I've got nothing.
  • 10:57 - 11:01
    OK. Now I want to talk a little bit more about editing context.
  • 11:01 - 11:04
    - Actually I do have...are you going to cover the page with name?
  • 11:04 - 11:08
    - Yes.
    - OK. Nothing more about generics right now.
  • 11:09 - 11:15
    OK, so here is how most people start out writing web applications.
  • 11:15 - 11:18
    How I started out writing Web Objects applications.
  • 11:18 - 11:21
    Session default editing context, all over the place.
  • 11:21 - 11:23
    This is how it usually works out.
  • 11:23 - 11:26
    You've got one session, one editing context.
  • 11:26 - 11:28
    Every page is tied to the editing context,
  • 11:28 - 11:31
    and the editing context is tied to the objects store.
  • 11:33 - 11:36
    Web Objects has a lot of methods that say defaults.
  • 11:36 - 11:37
    It's got a default modeling group,
  • 11:37 - 11:38
    a default shared editing context,
  • 11:38 - 11:41
    a default editing context.
  • 11:41 - 11:43
    A lot of these aren't very good defaults.
  • 11:43 - 11:45
    They're good to get you going,
  • 11:45 - 11:47
    but they're not something you want to be using long term.
  • 11:47 - 11:52
    Let's take a look at some of the problems that you're going to get in with this.
  • 11:53 - 11:55
    The dirty sandbox syndrome.
  • 11:55 - 11:56
    You go outside to play in your sandbox,
  • 11:56 - 12:00
    and the dog's been using it as a toilet.
  • 12:04 - 12:07
    The same thing happens with your editing context.
  • 12:07 - 12:10
    The user's in there, they get a validation error, they get cheesed off.
  • 12:10 - 12:14
    They go to the menu, they click some place else, they do something else,
  • 12:14 - 12:16
    and then they get the same validation error.
  • 12:16 - 12:20
    Because now the editing context is stuck. It's dirty.
  • 12:20 - 12:24
    You can avoid this. You can call editing context revert.
  • 12:24 - 12:26
    But you have to be pretty careful to do it,
  • 12:26 - 12:28
    because you never know when the user is going to back up,
  • 12:28 - 12:29
    and then they click the menu a bit.
  • 12:29 - 12:32
    If you don't call at the right time then their session gets stuck,
  • 12:32 - 12:35
    and they have to log out and log back in again.
  • 12:35 - 12:39
    That's the number one reason to avoid using a session default editing context.
  • 12:39 - 12:42
    Another reason is data freshness.
  • 12:42 - 12:49
    There's a concept of a default lag, a default fetch lag and a default timestamp in the editing context.
  • 12:49 - 12:52
    When you bring data into the editing context
  • 12:52 - 12:55
    it says, OK, I really only want data that's older than this.
  • 12:55 - 12:58
    Now, if you take Web Objects out of the box,
  • 12:58 - 13:01
    that's an hour before the user logged in.
  • 13:01 - 13:04
    If the user's been using your app for a half an hour,
  • 13:04 - 13:07
    they could be looking at data that's an hour and a half old.
  • 13:07 - 13:14
    Unless you've been doing refreshing fetches. I hate that phrase.
  • 13:16 - 13:21
    That's another problem with the default editing context, is it's as old as the session, and so is the data.
  • 13:23 - 13:28
    Excess data. This was really a problem, historically. It's not as bad now.
  • 13:28 - 13:31
    But the more objects you have in your editing context,
  • 13:31 - 13:34
    the more chances are related to each other,
  • 13:34 - 13:37
    and there's a greater chance that stuff's not going to go to scope.
  • 13:37 - 13:39
    It's not going to get garbage collected.
  • 13:39 - 13:42
    You're going to have a bigger memory footprint.
  • 13:42 - 13:44
    The best practice here,
  • 13:45 - 13:47
    I said the best practice
  • 13:47 - 13:54
    is to keep the session default editing context for read only session scope data.
  • 13:54 - 13:58
    Classically, this is the logged in user, their permissions,
  • 13:58 - 14:04
    information like that that applies to the whole session and is not going to change.
  • 14:07 - 14:08
    No objections? OK.
  • 14:08 - 14:10
    You guys aren't much fun today.
  • 14:10 - 14:12
    I save some good ones for later.
  • 14:12 - 14:17
    OK. Now, if you've moved beyond the session default editing context,
  • 14:17 - 14:20
    this is the most common thing to do.
  • 14:20 - 14:23
    Now, you notice the session's just sitting out there all alone.
  • 14:23 - 14:26
    There's nothing attached to it, it's just hanging out.
  • 14:26 - 14:29
    Instead of one editing context, we have a whole bunch.
  • 14:29 - 14:31
    We have one editing context for each page,
  • 14:31 - 14:35
    and each editing context is hooked up to the object store,
  • 14:35 - 14:37
    which is where things go up to the database.
  • 14:37 - 14:41
    Now, because these editing contexts are all equally associated with the page,
  • 14:41 - 14:45
    all equally associated with the data score, they're called peer editing contexts.
  • 14:45 - 14:48
    Now, I'll warn you about a couple things here.
  • 14:48 - 14:51
    If you have an object in one editing context,
  • 14:51 - 14:56
    you can't make a relationship to an object in another editing context.
  • 14:56 - 14:58
    Which is one of the things that Mike fixed in Wonder,
  • 14:58 - 15:02
    with his inverse relation...no. Oh, no. That was in...
  • 15:02 - 15:05
    - [indecipherable]
    - Year X generic records.
  • 15:05 - 15:09
    - Yeah. Yeah.
    - That's something you have to be careful of.
  • 15:09 - 15:13
    - The other thing is, if...
    - [indecipherable] We didn't fix it as much as,
  • 15:13 - 15:17
    we just throw an exception immediately. We fail fast.
  • 15:17 - 15:22
    - Yes, you're right.
    - We don't try to...fixing it is nearly impossible.
  • 15:22 - 15:24
    You can't make your relationship between two things.
  • 15:24 - 15:27
    You need to copy objects from one editing context to another.
  • 15:27 - 15:29
    Now, that's a little bit of work,
  • 15:29 - 15:34
    and a few things are, it isolates the changes.
  • 15:34 - 15:36
    You don't have any more dirty sandbox syndrome.
  • 15:36 - 15:40
    Because each editing context is directly associated with one page,
  • 15:40 - 15:43
    the worst thing that's going to happen is that that one page is going to get stuck with
  • 15:43 - 15:47
    the validation errors for the data they typed in.
  • 15:47 - 15:50
    The second thing is data freshness.
  • 15:50 - 15:54
    You create an editing context for each page, so if you want,
  • 15:54 - 15:57
    the data can only be as old as that page is.
  • 15:57 - 15:59
    No effort of yours at all.
  • 15:59 - 16:01
    Create the page normally, it'll get fresh data.
  • 16:01 - 16:03
    You don't have to do any refreshing fetches,
  • 16:03 - 16:05
    you don't have to worry about it.
  • 16:07 - 16:10
    It's because the editing context is attached to the page,
  • 16:10 - 16:12
    not to the session.
  • 16:12 - 16:15
    The editing context gets thrown away when the page gets thrown away,
  • 16:15 - 16:18
    not when the user logs out.
  • 16:18 - 16:24
    Which means that you have fewer editing contexts and fewer objects in editing contexts.
  • 16:25 - 16:27
    Now, a couple of best practices.
  • 16:27 - 16:30
    Because you want the editing context to be discovered with the page,
  • 16:30 - 16:32
    you want a small page cache.
  • 16:32 - 16:35
    The default is something like 30 pages, I think.
  • 16:35 - 16:37
    Which is way more than enough.
  • 16:37 - 16:40
    Because very few users are going to be dedicated enough,
  • 16:40 - 16:42
    rather than going to the menu to go
  • 16:42 - 16:47
    back, back, back, back, back, back, back, 30 times.
  • 16:47 - 16:50
    Probably not going to happen. Five is usually enough.
  • 16:50 - 16:53
    Keep the page cache small...and locking.
  • 16:53 - 16:57
    If you were using peer editing contexts, you must lock.
  • 16:57 - 16:59
    OK? Locking isn't a best practice,
  • 16:59 - 17:04
    locking is a, do it or your app will explode and burn.
  • 17:04 - 17:07
    You have to lock, it's not an option.
    OK.
  • 17:07 - 17:10
    The best practice is, don't do it yourself.
  • 17:10 - 17:11
    Don't try and do it in the wake,
  • 17:11 - 17:13
    don't try and do it for sleep, you're going to screw it up.
  • 17:13 - 17:16
    You're going to make a mistake, your app will deadlock.
  • 17:16 - 17:20
    It's been done, it's been tested, it's right. Use it.
  • 17:20 - 17:23
    If you're using Wonder, or if you're inclined to be using Wonder,
  • 17:23 - 17:25
    ERXEC is a fine solution for it.
  • 17:25 - 17:29
    If for some reason you don't want to be using Wonder, you can't use Wonder,
  • 17:29 - 17:32
    there's a class floating around called the Multi‑EC Lock Manager.
  • 17:32 - 17:38
    I'm not fully married to Wonder yet. We're just dating on the side.
  • 17:38 - 17:41
    My class uses Multi‑EC Lock Manager.
  • 17:43 - 17:45
    Anything else?
  • 17:46 - 17:48
    I should have put in more fiery topics.
  • 17:48 - 17:53
    - In the navigation destination of architecture I discussed before,
  • 17:53 - 17:57
    I just flashed a EC on every pop of that stack,
  • 17:57 - 18:01
    and it's resolved the data freshness issue in that system.
  • 18:03 - 18:06
    - Yeah. You can do it, but it's tricky.
  • 18:08 - 18:11
    Oh, I forgot that.
  • 18:11 - 18:13
    I forgot my most important point.
  • 18:13 - 18:15
    Remember before we were talking about having the page,
  • 18:15 - 18:18
    and having an editing context method on the page?
  • 18:18 - 18:19
    If you do that,
  • 18:19 - 18:23
    it's very easy to change the implementation of your editing context method and say,
  • 18:23 - 18:26
    "OK. I'm going to switch from the sessions default editing context.
  • 18:26 - 18:28
    Now I'm going to use a peer one,"
  • 18:28 - 18:30
    and it goes right down through all the components in the page.
  • 18:30 - 18:33
    - Yes?
    - May I ask about this...
  • 18:33 - 18:40
    I have...A page comes up, and user does a bunch of stuff on Page A.
  • 18:40 - 18:43
    He gets a lot of records [indecipherable]
  • 18:43 - 18:45
    Then we go to Page B,
  • 18:45 - 18:48
    and they really want all the records from the first pages
  • 18:48 - 18:51
    set up a whole bunch of stuff.
  • 18:51 - 18:56
    Now you do, obviously, get the records from page B without going back to categories.
  • 18:56 - 19:00
    - Yes. Well, it depends. It depends who you ask.
  • 19:00 - 19:04
    - Oh. How do you know that?
  • 19:04 - 19:07
    Do you do some copy from your old?
  • 19:07 - 19:09
    How do you get to the records that are on page A,
  • 19:09 - 19:14
    or page B without doing all this database refreshing
  • 19:14 - 19:21
    and tree walking and all sorts of stuff to create this particularly useful tree?
  • 19:21 - 19:25
    - You can either pass them an array using a method like...
  • 19:25 - 19:29
    - It's component to component, so you have to go through the session
  • 19:29 - 19:36
    to get that because you have no idea whether you got to component B through
  • 19:36 - 19:39
    direction action request or from page A or who knows were.
  • 19:39 - 19:42
    - Are you talking about moving from one page to another page?
  • 19:42 - 19:45
    - When page A goes to page B it can pass the data.
  • 19:46 - 19:51
    - There's no problem putting data into your session....well, there are problems.
  • 19:51 - 19:54
    There's no intrinsic EOF problem with putting data into your sessions
  • 19:54 - 19:57
    when fetched with a non session editing context.
  • 19:57 - 19:59
    You could fetch it on page A.
  • 19:59 - 20:01
    If it truly is session state data,
  • 20:01 - 20:06
    you could push it into your session and leave it in the editing context that you fetched it with.
  • 20:06 - 20:09
    You just have to make sure that you lock it again when you try to touch that data.
  • 20:09 - 20:12
    Or you could local instance into your sessions of auditing context.
  • 20:12 - 20:14
    A lot of it depends on what you want to do.
  • 20:14 - 20:19
    We find that it's very rare that we have session level data
  • 20:19 - 20:22
    that we pass the data between components as part of the action.
  • 20:22 - 20:24
    - Other than the user.
    - Other than the user, yeah.
  • 20:24 - 20:27
    Every once in a while there's some crazy problem
  • 20:27 - 20:31
    where you really just have to push in the session because it's just very tricky,
  • 20:31 - 20:36
    but that's by far the exception in my experiences.
  • 20:36 - 20:42
    - Yeah.
    - Did that answer your question at all?
  • 20:42 - 20:45
    - Well, I'll look at it. I have a very complex financial application
  • 20:45 - 20:49
    that gets built up as the user is working on it more and more.
  • 20:49 - 20:58
    He may be on page M. He's using lots of stuff he's done on pages A, F, and G on page M.
  • 20:58 - 21:02
    - If that were me I would actually create a new class
  • 21:02 - 21:06
    that encapsulates all the state for this multiple page transaction
  • 21:06 - 21:09
    and pass that object between pages.
  • 21:09 - 21:13
    Because the problem is as soon as you put something into the session it presumes that it is session wide.
  • 21:13 - 21:17
    It's very possible that you go into another page that it's not actually a part of.
  • 21:17 - 21:22
    Now things are confused because it's presuming to get session data and you get a race condition.
  • 21:23 - 21:25
    But this is actually very application...
  • 21:25 - 21:30
    - I was thinking more of what's in the EC rather than sessions.
  • 21:30 - 21:34
    - Are you talking about like a multi‑step process?
    - Yeah.
  • 21:34 - 21:36
    - OK, wait a second.
  • 21:38 - 21:41
    The next slide may answer your question.
  • 21:41 - 21:43
    Now this is the alternate step,
  • 21:43 - 21:49
    the alternate organization when you're not using the default editing context.
  • 21:49 - 21:53
    Same as before, sessions is out there all by itself doing its session thing.
  • 21:54 - 21:59
    What we've introduced here is we've introduced another layer of editing context.
  • 22:00 - 22:02
    The pages are tied to an editing context,
  • 22:02 - 22:05
    but that editing context doesn't go directly to the object store.
  • 22:05 - 22:07
    It goes to another editing context
  • 22:07 - 22:09
    and that one there goes to the object store.
  • 22:09 - 22:14
    In order to actually get changes saved doing something like this,
  • 22:14 - 22:17
    you actually have to do two saves,
  • 22:17 - 22:25
    the first save on the child editing context that moves to the parent,
  • 22:25 - 22:30
    the second save gets called in the parent and moves it off to the object store.
  • 22:30 - 22:33
    This can be very useful in some situations.
  • 22:33 - 22:39
    I don't use it very often, maybe a couple of times an application for what I normally do.
  • 22:41 - 22:44
    The big advantage for this, at least in my experience,
  • 22:44 - 22:49
    has been that you get EOF validation without actually sending anything to the database.
  • 22:49 - 22:52
    It's almost like a two phase commit.
  • 22:52 - 22:56
    When you call save changes on the child editing context,
  • 22:56 - 22:58
    it goes through all the EOF validation,
  • 22:58 - 23:02
    calls your validate for save, does all the model validations,
  • 23:02 - 23:06
    does everything it would normally do running out to the database but then it doesn't.
  • 23:06 - 23:08
    It writes it into the parent editing context.
  • 23:12 - 23:15
    I usually only use this for processes that have multiple steps in them
  • 23:15 - 23:19
    where each step is on a page and there are enough things going on on a page that
  • 23:19 - 23:24
    if anything is wrong you want the user to correct it there before they go on.
  • 23:24 - 23:27
    Wizards are a good example.
  • 23:29 - 23:34
    Some best practices for this, again, you have to lock it.
  • 23:35 - 23:38
    Don't do it yourself. Use one of the tools out there.
  • 23:40 - 23:46
    The editing context method on the page should usually return the child editing context.
  • 23:46 - 23:53
    Somewhere on the very last page where the user says, "OK, all of this is right, do it,"
  • 23:53 - 23:56
    you want to have a parent editing context method
  • 23:56 - 24:01
    calling saved changes and that flushes things out into the database.
  • 24:01 - 24:03
    Now one thing I'll mention here is that
  • 24:03 - 24:08
    if you read the documentation you'll see the locking thing is a bit iffy.
  • 24:08 - 24:12
    If you lock the child, you don't have to lock the parent.
  • 24:12 - 24:17
    My advice to you is forget about it, lock the parent.
    Don't even think about it, just lock it.
  • 24:18 - 24:22
    You'll never be wrong like that. It's find to lock the parent, just lock everything.
  • 24:23 - 24:25
    Did that answer your question at all?
  • 24:25 - 24:28
    Is that getting any closer to what you're looking for?
  • 24:31 - 24:33
    Everybody happy over here.
  • 24:34 - 24:39
    - On the lock, the documentation is actually right, though? You don't have to go to parent?
  • 24:39 - 24:43
    - No, no, the documentation is right. I didn't say it was wrong. I just said...
  • 24:43 - 24:47
    - He just doesn't trust it.
    - Rather than worrying about it, just see an editing context, lock it.
  • 24:47 - 24:53
    - I agree.
    - If you can see it, lock it.
  • 24:53 - 24:57
    OK, now this gets back into Mike's neat little trick here.
  • 24:57 - 25:02
    - I'm not really sure if Mike gave this to me or not but...
    - Yes.
  • 25:02 - 25:05
    - This is how I started out creating pages in my web app.
  • 25:05 - 25:08
    You know? I'm in page A.
    You want to move to page B.
  • 25:08 - 25:12
    Page with name, search page. What's wrong with it?
  • 25:14 - 25:17
    Refactoring, you're using a magic string.
  • 25:17 - 25:20
    Sooner or later you're going to go through there and you're going to realize,
  • 25:20 - 25:24
    "Well, that's actually old search page and I'm going to use new search page for most of my stuff."
  • 25:24 - 25:27
    Then all of a sudden all of your apps are broken but you don't know.
  • 25:27 - 25:31
    You have to go click through every link or do a search and replace and try to find them.
  • 25:31 - 25:36
    Why do that? Make the computer do the work for you.
  • 25:36 - 25:41
    The best practice is when you're doing page with name, do something like this.
  • 25:41 - 25:44
    Searchpage.class.getname.
  • 25:44 - 25:46
    It works exactly the same as that one but
  • 25:46 - 25:50
    when you enter eclipse and you refactor that pages name,
  • 25:50 - 25:52
    it's going to refactor the Java class.
  • 25:52 - 25:54
    It's going to refactor the wool file, the template, the HTML,
  • 25:54 - 25:58
    the DWAD, and it's also going to fix that for you too.
  • 25:58 - 26:01
    If you're silly enough to go into finder and do it in finder,
  • 26:01 - 26:04
    at the very least the next time you compile you're
  • 26:04 - 26:07
    going to get a bunch of compile time errors.
  • 26:07 - 26:12
    Now, with Java 1.5 we can go one better than that.
  • 26:15 - 26:20
    That's a lovely bit of generics code. I love how generic code is almost unreadable.
  • 26:22 - 26:26
    Every time I look at code like that I go, "Ohhhhh."
  • 26:26 - 26:30
    But there's one good thing about generic code.
  • 26:31 - 26:34
    It's really nice to use.
  • 26:34 - 26:38
    You can put that method up in your super class common page component.
  • 26:38 - 26:42
    Now when you create pages now it's shorter.
  • 26:42 - 26:45
    You just have to save page with class, my page dot class. There's no casting.
  • 26:45 - 26:51
    - You probably don't want it to be private in your version, just for the record.
  • 26:53 - 26:57
    - I'm going to put that as a best practice.
    - Now who typed that?
  • 26:58 - 27:00
    OK, forget the private part. That should be public.
  • 27:00 - 27:03
    I'm not really too sure why that says private.
  • 27:03 - 27:06
    I copied that from some place.
    That's my story.
  • 27:06 - 27:09
    - Well, the funny part is it's like a copy from something I have seen before,
  • 27:09 - 27:13
    but the private you actually had to change, go out of your way to do it.
  • 27:13 - 27:15
    - No, I didn't actually copy it from your stuff.
  • 27:15 - 27:19
    I think I know who to blame, but I won't mention the name.
  • 27:23 - 27:26
    - Yeah, yeah, it was him.
    - What's that again?
  • 27:29 - 27:33
    Your X direct action has that method too as well as your X component for the record.
  • 27:35 - 27:40
    - OK, this topic might generate a bit more fire than the other topics.
  • 27:43 - 27:46
    Your components are your view.
  • 27:46 - 27:49
    They're not your controller. They're not your model. Keep them clean.
  • 27:49 - 27:53
    I don't think I've ever seen any web objects application
  • 27:53 - 27:59
    other than a few that I wrote that didn't vigorously, vigorously violate this rule.
  • 27:59 - 28:02
    Some worse than others, but all of them to some degree.
  • 28:03 - 28:06
    Your component is a view. Your component is a view.
  • 28:09 - 28:12
    You shouldn't be calling any methods in EO control ever.
  • 28:13 - 28:19
    The only thing in EO control you should ever have reference to in your page is editing context.
  • 28:20 - 28:24
    If you have any methods or any code in your page that's calling something else in EO control,
  • 28:24 - 28:26
    it's in the wrong place.
    Move it.
  • 28:26 - 28:28
    Move it to an EO.
    Move it to a controller class.
  • 28:28 - 28:32
    Move it to a business process.
    Move it out of your page.
  • 28:35 - 28:39
    Absolutely, positively, under no circumstances
  • 28:40 - 28:43
    will you call anything in EO access on your page.
  • 28:43 - 28:45
    That's really, really bad. Again, if you're doing that,
  • 28:45 - 28:48
    it's in the wrong place.
    Move it out.
  • 28:48 - 28:53
    Put it in your EO. Put it someplace else. It doesn't belong on your page.
  • 28:54 - 28:58
    The only thing you should be calling on your page that's not direction on your page are
  • 28:58 - 29:01
    simple methods on your enterprise object.
  • 29:01 - 29:02
    That doesn't mean,
  • 29:02 - 29:05
    OK, enterprise object.
    OK, enterprise object give me that.
  • 29:05 - 29:07
    I've got to do a bunch of calculations,
  • 29:07 - 29:09
    and then I'm going to put it back in an enterprise object.
  • 29:10 - 29:13
    That's not the job of the page.
    The page is to show things
  • 29:13 - 29:18
    If you have anything other than just simple copying things into the UI,
  • 29:18 - 29:20
    it's in the wrong place.
  • 29:22 - 29:28
    Now so your best practice is if the code is not directly supporting the HTML generation,
  • 29:28 - 29:34
    if the only purpose is not to support the HTML generation, it's in the wrong class.
  • 29:34 - 29:36
    Move it.
  • 29:38 - 29:40
    I might have some fun here.
  • 29:40 - 29:42
    You don't do this, do you?
  • 29:44 - 29:47
    The advantage of this is your pages are really simple.
  • 29:48 - 29:51
    You don't need to unit test your pages because they're really simple.
  • 29:52 - 29:55
    You don't need to debug your pages because they're really simple.
  • 29:55 - 29:58
    There should be very little code on a page.
  • 29:58 - 30:00
    - I don't know about that one.
  • 30:00 - 30:02
    - OK, there should be very little code on a simple page.
  • 30:02 - 30:08
    - I mean the testing.
    - I know. I'll convince you one of these days.
  • 30:08 - 30:10
    Any comments?
  • 30:11 - 30:14
    No shrieks? I thought that one would get some shrieks at least.
  • 30:14 - 30:18
    - I think most people agree. It's just whether you live up to the ideal or not.
  • 30:18 - 30:27
    - I do agree. This is really where I go and we all aim to do that. But sometimes we just...
  • 30:27 - 30:29
    - I always do that.
  • 30:29 - 30:34
    - If you look at his code, he does it. He's like the only person in the world to do that.
  • 30:34 - 30:37
    - But I'm not standing on that scaffold.
  • 30:39 - 30:44
    OK. This is a very quick security thing maybe everybody is not aware of.
  • 30:45 - 30:49
    If you make URL like this web objects won't generate it for you, you have to type it yourself.
  • 30:50 - 30:53
    If you type any page name you can go directly to it,
  • 30:53 - 30:57
    even if the user has no links, has no permissions, has nothing,
  • 30:57 - 30:59
    Web Objects will show it to them.
  • 30:59 - 31:05
    Usually it's not a really big problem because most pages need some data, they need some set‑up.
  • 31:05 - 31:08
    What the user is going to get is an exception page probably.
  • 31:08 - 31:10
    But they might not.
  • 31:10 - 31:15
    They may also have to guess the name of your page which maybe isn't so easy.
  • 31:15 - 31:19
    Just in the interest of keeping everything secure and tidy,
  • 31:19 - 31:24
    you can put this rather messy method in your application class.
  • 31:24 - 31:29
    If anybody tries doing something like that, it will just send them off to your main page.
  • 31:29 - 31:34
    You can, of course, replace main with anything else that you want to show?
  • 31:48 - 31:50
    - Actually, no. That one shouldn't,
  • 31:50 - 31:52
    because you don't know what class it is.
  • 31:52 - 31:54
    He's actually right on that one.
  • 31:54 - 31:57
    If this is reusable code that's in your base component,
  • 31:57 - 31:59
    main needs to be dynamically resolved in this case.
  • 31:59 - 32:03
    If you do a ".class reference," it will be guaranteed to be wrong.
  • 32:03 - 32:06
    Because main, you have in each of your apps.
  • 32:06 - 32:09
    I'll give you a shout out that we allow that in the other case.
  • 32:09 - 32:11
    - Thank you.
    - Chuck is in the right...
  • 32:11 - 32:14
    However, what I will say is your ex‑component has a slight variation on this.
  • 32:14 - 32:19
    It's actually potentially desirable to be able to do this sometimes.
  • 32:19 - 32:25
    Your X component has a "is page access allowed" method, that defaults to "return true."
  • 32:25 - 32:31
    The intent is that in your classes, you extend and provide a "my page" component.
  • 32:31 - 32:36
    You have your non‑page components and your page component super classes,
  • 32:36 - 32:39
    and your non‑page component classes return false for that,
  • 32:39 - 32:43
    it'll actually throw a security exception, if you attempt to do that.
  • 32:43 - 32:48
    - OK.
    - Yeah. That's all.
  • 32:56 - 32:58
    - You can do that, too.
  • 32:58 - 33:02
    Usually, what I do is I return something I look up from a property,
  • 33:03 - 33:07
    but I didn't want to go into a big long explanation about why that was.
  • 33:07 - 33:09
    I just cheated.
  • 33:10 - 33:13
    - I'm curious whether, something we talked about a long ago,
  • 33:13 - 33:16
    anything you can reach to get direct action or
  • 33:16 - 33:20
    anything you do as a result the direct action access to your app?
  • 33:20 - 33:25
    If it generates very much work, it can lead to a denial of service attack.
  • 33:25 - 33:29
    I've never heard of that other than it's a theoretical possibility.
  • 33:29 - 33:32
    I'd be curious if anybody has actually bumped into that kind of thing.
  • 33:32 - 33:34
    - That's a good point.
  • 33:34 - 33:37
    - We should edit that out the DVD, so no one gets ideas.
  • 33:39 - 33:41
    - Just fix it in Wonder.
  • 33:44 - 33:48
    A little piece of advice that I've seen from a few apps is, "Expect problems."
  • 33:48 - 33:55
    The thing you want to remember is bad things happen to good code and that's yours...
  • 33:55 - 33:57
    I hope.
  • 33:57 - 34:02
    Come on quickie...OK. The things you should plan to handle as backtracking.
  • 34:02 - 34:05
    You saw it in Andrew's framework. He handles that.
  • 34:05 - 34:09
    It's easy to forget because you're a developer. You don't use the backtrack.
  • 34:09 - 34:10
    You always use all the controls you get.
  • 34:10 - 34:14
    It's easy to forget that the user is going to delete something and he's going to go,
  • 34:14 - 34:16
    "Oh, yeah, what was that I just deleted?
  • 34:16 - 34:21
    He's going to backup, take a look at it, and bad things will happen.
  • 34:21 - 34:26
    You really need to do something to make sure that you app handles backtracking.
  • 34:26 - 34:33
    As I discovered recently, Safari has a new bug in it and it doesn't work with this.
  • 34:33 - 34:36
    If you backtrack with Safari,
  • 34:36 - 34:38
    your app won't have any idea.
  • 34:38 - 34:42
    I haven't quite figured out what to do about that one, but it's not good.
  • 34:43 - 34:47
    - Safari had that back in the past a couple of years ago and they
  • 34:47 - 34:52
    changed that behavior again at that time.
  • 34:52 - 34:57
    Maybe it was introduced accidentally again and will go away.
  • 34:57 - 35:01
    It was in there, it was removed, and now it's back in?
  • 35:01 - 35:08
    - Yeah. It's clearly wrong. I expect it to be fixed, but for the immediate release it's a problem.
  • 35:10 - 35:14
    The other thing that people often forget to handle are errors and saved changes.
  • 35:14 - 35:18
    Even if you don't have very many validations in your model,
  • 35:18 - 35:22
    sooner or later something is going to happen. Saved changes is going to throw an exception.
  • 35:22 - 35:27
    When you call saved changes, you should always wrap in a try‑catch and do something with it.
  • 35:27 - 35:30
    Don't just assume that it's going to be OK,
  • 35:30 - 35:33
    because your database will go down. Something will happen.
  • 35:33 - 35:35
    Just some general advice,
  • 35:35 - 35:38
    "Bad things happen to good code. Plan ahead."
  • 35:42 - 35:46
    OK. Now we're going to switchover to EOF.
  • 35:46 - 35:49
    Mike stole some of these things in his presentation.
  • 35:49 - 35:54
    OK. The same thing we were talking about with components, use inheritance.
  • 35:55 - 35:59
    EO Generic record is great, but if you start using it for very much
  • 35:59 - 36:02
    you're going to find you have a bunch of common code all over the place.
  • 36:02 - 36:04
    You should provide a subclass for it.
  • 36:04 - 36:09
    Some ideas of things that you will find useful to put in your subclass,
  • 36:09 - 36:14
    a code to copy one EO, make a new EO as a copy of an existing one.
  • 36:18 - 36:20
    Some caching control.
  • 36:20 - 36:24
    It's often useful when you have very expensive values, to be able to cache them in the EO.
  • 36:24 - 36:28
    The problem is that, as data changes, the cache won't be fresh anymore.
  • 36:28 - 36:31
    You can do some things in the generic record subclass
  • 36:31 - 36:35
    to catch certain EOF notification and tell your object,
  • 36:35 - 36:39
    "OK. It's time to get rid of that data and recalculate it." Yes?
  • 36:48 - 36:50
    You can't define the generic clone,
  • 36:50 - 36:55
    but you can come up with a lot of code that makes it very easy to write a copy method.
  • 37:03 - 37:06
    It's in the practical utilities book.
  • 37:07 - 37:10
    I just put a bunch of that stuff in that class.
  • 37:11 - 37:15
    Global ID's. This is something that when you start using peer‑editing context,
  • 37:15 - 37:18
    you start using child. You want the global idea of objects,
  • 37:18 - 37:23
    usually it's "editing context.globalidforobject.EO."
  • 37:23 - 37:25
    It makes it a lot easier just to package it up.
  • 37:25 - 37:26
    Shove it in your super class,
  • 37:26 - 37:29
    and you never have to worry about it again.
  • 37:29 - 37:31
    Related to that is...
  • 37:32 - 37:34
    I think I broke your clicker thing...
  • 37:34 - 37:39
    is an "is new" method, which just calls is temporary object.
  • 37:39 - 37:45
    Rather than having "editingcontext.globalidforobject.EO.istemporary"
  • 37:45 - 37:50
    your code is a lot easier to read if you put in a method like "is new."
  • 37:51 - 37:52
    Validation extensions.
  • 37:52 - 37:56
    I've never liked the API for validate for save.
  • 37:56 - 37:59
    I always found it really painful, because you've got to call super.
  • 37:59 - 38:01
    See if there's exceptions or not, and then add them. Make another and...
  • 38:01 - 38:06
    What I've done is I've made a method that has a different API on my super class.
  • 38:06 - 38:12
    It handles all the paperwork for you. You just have to give it an array of exceptions.
  • 38:13 - 38:15
    Whoops, went too far.
  • 38:15 - 38:18
    Again, define things that you want to put in your own super class.
  • 38:18 - 38:22
    The best thing is to look at what people have done before you.
  • 38:22 - 38:27
    ERX generic record is a good place to steal things from, if you're not using it.
  • 38:27 - 38:30
    There is one in the GVC frameworks.
  • 38:30 - 38:33
    There's several other one's out there.
  • 38:33 - 38:38
    If you don't have something like this, go search through them and find some good ideas for yours.
  • 38:38 - 38:41
    If you do have something, you'll probably find something new.
  • 38:41 - 38:44
    I've ripped off a few things, from Wonder. Thank you.
  • 38:44 - 38:46
    - And likewise.
  • 38:48 - 38:53
    - It's all one big cross pollination.
    - There's a new ERX copying coming in. Quite soon actually
  • 38:53 - 38:56
    - Oh, I wonder where that came from?
  • 38:58 - 39:01
    Thank you. I'll give a little diagram here.
  • 39:01 - 39:06
    We were talking before about the generation gap pattern.
  • 39:06 - 39:13
    Up on the top, we EO generic record that comes with Web objects and does everything that you need to do.
  • 39:13 - 39:14
    There's your common EO.
  • 39:14 - 39:18
    That's all the cool stuff you have the Web objects to make your Web objects easier to read,
  • 39:18 - 39:20
    to make it easier to write.
  • 39:20 - 39:23
    Here, we come in with the generation groups.
  • 39:23 - 39:26
    We saw over here, we have group entity, which is in the EO model.
  • 39:26 - 39:32
    That's a definition for the editing and that's used to generate an underscored group Java.
  • 39:32 - 39:37
    The model definition and the underscore class reflect what's in each other.
  • 39:37 - 39:40
    You never touch that. That just gets generated.
  • 39:40 - 39:46
    Down there at the bottom, that's the class you actually use in your app.
  • 39:46 - 39:51
    That's all of your custom code and goes into "group.javaclass."
  • 39:51 - 39:55
    I want to talk about leveraging EO generation.
  • 39:56 - 40:00
    When you were using an EO modeler, there wasn't very much you could do.
  • 40:00 - 40:02
    It just made the accessor methods and mutator methods.
  • 40:02 - 40:04
    There wasn't very much in it.
  • 40:04 - 40:09
    Now that we have all these cool templates, there's a lot of interesting things you can do.
  • 40:10 - 40:15
    Checks for editing context equality, which is what you added in Wonder.
  • 40:15 - 40:19
    If you don't want it there, you can generate it into you classes.
  • 40:19 - 40:20
    It means, next time
  • 40:20 - 40:25
    your app tries to make a connection between two EOs and two different editing contexts...
  • 40:25 - 40:31
    Boom! You find out about it right away, not several operations later.
  • 40:33 - 40:35
    If you're using peer‑editing context,
  • 40:35 - 40:37
    if you're using nesting edited context,
  • 40:37 - 40:40
    you end up copying objects between editing contexts a lot, using local instance.
  • 40:40 - 40:45
    Of course, you have to cast it, because this is Java and everybody loves casting in Java.
  • 40:46 - 40:50
    You can easily add a local instance method into the generated code,
  • 40:50 - 40:53
    to properly cast it to the proper EO.
  • 40:54 - 40:58
    If you're not using Mike's really neat add objects to both sides of the relationship
  • 40:58 - 41:00
    with a really a long name with a Key or something or other.
  • 41:00 - 41:08
    You can generate code to make methods so it always connects both sides of the relationship.
  • 41:09 - 41:11
    Common fetches, I stole this one from Mike recently.
  • 41:11 - 41:15
    - Andrea thinks you should use the class pattern, though.
    - Pardon?
  • 41:16 - 41:21
    -Never mind, OK. Andrea's not here, so we're all in agreement.
    - OK.
  • 41:23 - 41:27
    It's not many EOs that you have either one of these particular fetches for them.
  • 41:27 - 41:31
    Fetch me all the EOs sorted like this. Fetch me all the EOs with this qualifier.
  • 41:31 - 41:34
    Fetch me all the EOs of this qualifier sorted like this.
  • 41:34 - 41:38
    It's very easy to get methods like that generated for you.
  • 41:38 - 41:42
    Those fetches returns everything nice and casted properly.
  • 41:43 - 41:48
    I haven't actually done this one, but it's been sitting on my desk as something to do for a while.
  • 41:48 - 41:50
    You might want to think about it for entity modeler
  • 41:50 - 41:54
    and to be able to define defaults for the attributes in it,
  • 41:54 - 41:58
    and get that generated into awake for insertion.
  • 41:58 - 42:00
    - Wonder who has something like this.
  • 42:00 - 42:02
    This is part of the thing that Andrea always yells at me about,
  • 42:02 - 42:06
    that I don't use right now. I'll have to look at that and see how it all fits.
  • 42:06 - 42:15
    - Yes, I agree in principle.
    - You should probably modify the format to actually accoomodate that directly into system.
  • 42:15 - 42:17
    - Yeah. It would be a good addition.
  • 42:17 - 42:20
    In the meantime, you can stick them in the user info and generate them out.
  • 42:20 - 42:24
    It would be nice to have them official.
  • 42:27 - 42:33
    To get ideas of what you can do, Mike's templates. Mike's a very creative guy in WOLIPS
  • 42:33 - 42:36
    - Those are, by the way, Jonathan Rich's templates.
    - Those are John Rich's?
  • 42:36 - 42:41
    - I mean, like the base version. It's 75 percent his and other stuff.
  • 42:41 - 42:43
    - Anyway, I stole a lot of really cool stuff out of those.
  • 42:43 - 42:48
    - We're stealing from lots of them. We're standing on the shoulders like thieves.
  • 42:48 - 42:51
    - That's what Web Objects is all about, cross thievery!
  • 42:54 - 42:59
    OK. Now, again, when we get back to the way people start doing things.
  • 42:59 - 43:06
    The old fetch specifications, your order thing. It's the same problem you had before with the "page for" name.
  • 43:06 - 43:07
    You got a magic string in there.
  • 43:07 - 43:12
    Eventually, you're going to go in and you're going to change the name of the entity or change the name of the attribute.
  • 43:12 - 43:18
    Voila! Your code's broken. You don't know until you run it.
  • 43:19 - 43:25
    You can get the generated files to includes constants like this,
  • 43:25 - 43:29
    where it defines an entity name for order.
  • 43:29 - 43:36
    Then use it like that. When you re‑factor it
  • 43:36 - 43:38
    in the code, it automatically updates it everywhere.
  • 43:38 - 43:41
    You don't have instantly broken code,
  • 43:41 - 43:45
    getting the compiler to work for you.
  • 43:46 - 43:50
    Following on with that qualifier for format.
    Bad, bad, bad!
  • 43:50 - 43:53
    It's just a fine source of re‑factoring bugs. That's all it is.
  • 43:53 - 43:56
    It looks really convenient when you start using this,
  • 43:56 - 43:58
    "Whoa, I can do all kinds of things with EO qualifier. With format,
  • 43:58 - 44:02
    I don't have to write all these horribly long qualifiers."
  • 44:02 - 44:04
    Missing a quote?
  • 44:06 - 44:07
    Damm...
  • 44:10 - 44:12
    What idiot typed this?
  • 44:14 - 44:17
    Clearly, I don't use these.
  • 44:21 - 44:25
    That's in version 9 I think.
  • 44:25 - 44:28
    Rather than do that, you should write out the qualifier long hand.
  • 44:28 - 44:35
    Mike mentioned that whoever wrote these classes, really, really liked typing.
  • 44:35 - 44:38
    They like typing more than anything.
  • 44:38 - 44:40
    Even if you're not using much of Wonder,
  • 44:40 - 44:44
    you should at least use this utility class,
  • 44:44 - 44:48
    because it makes writing things so much easier and shorter.
  • 44:48 - 44:51
    - You can use EQ, even.
    - EQ?
  • 44:51 - 44:56
    - Instead of equals.
    - OK. I like typing a little bit!
  • 44:56 - 44:59
    - We provide both.
  • 44:59 - 45:01
    We let you choose which one you prefer.
  • 45:01 - 45:05
    Anyway, thanks to Mike for making my code much shorter and easier to read.
  • 45:05 - 45:08
    And It's also easy to re‑factor.
  • 45:09 - 45:12
    - It's not actually that somebody likes to type.
  • 45:12 - 45:17
    It's that it's so easy to throw these in a line together at objective C.
  • 45:17 - 45:22
    You get selector, selector, selector, selector going on forever and it behaves perfectly.
  • 45:22 - 45:26
    - Then it translates to java what do you get?
    - A mess.
  • 45:26 - 45:29
    Something, something, some...all stuck together with camelcase.
  • 45:29 - 45:35
    - That's a good point.
    - It's not that they like to type, it's that you couldn't get any of the...
  • 45:36 - 45:39
    - Objective C, it made a lot more sense.
    - Yeah, it did.
  • 45:39 - 45:43
    - That's where we move objects from both sides of the relationship with key.
  • 45:43 - 45:47
    - An Objective C was all broken up.
    - In know. I did Objective C. I remember.
  • 45:47 - 45:50
    In Java, it's like,
  • 45:50 - 45:52
    "Add object to both sides of the relationship
  • 45:52 - 45:55
    with gratuitously long name that I have a really hard time remembering what it is key."
  • 45:55 - 46:01
    - It's an old joke at this point.
  • 46:02 - 46:05
    - Yeah. I don't have that many jokes. I have to recycle them.
  • 46:06 - 46:09
    - This is one, actually, where somebody yelled,
  • 46:09 - 46:12
    "Co‑completion." Yes, I totally agree that co‑completion makes this
  • 46:12 - 46:14
    less of a problem on the writing side,
  • 46:14 - 46:16
    but it doesn't make it any easier on the reading side.
  • 46:16 - 46:20
    When you write one qualifier, it basically fills the full width of your editor.
  • 46:20 - 46:25
    You're immediately scrolling to see what the second surprise qualifier is.
  • 46:28 - 46:33
    - OK. I really hope in 2008, I don't actually have to tell people this.
  • 46:33 - 46:35
    That this is the best practice.
  • 46:35 - 46:39
    I've recently found out that I probably do. I'm going to go through this quickly.
  • 46:39 - 46:43
    Use prototypes or you're stupid.
  • 46:46 - 46:49
    - There's a T‑shirt.
    - I really can't say it anymore simply than that.
  • 46:49 - 46:51
    Use prototypes or you're stupid!
  • 46:53 - 46:57
    For those two people in the audience not using prototypes,
  • 46:58 - 47:00
    they're templates for attributes.
  • 47:00 - 47:03
    That's basically what they are. It's a template for an attribute.
  • 47:03 - 47:04
    What can you do with the templates?
  • 47:04 - 47:07
    Faster model creation!
  • 47:07 - 47:11
    You're typing less, so you can concentrate more on the business stuff.
  • 47:11 - 47:14
    Less on filling out all the fiddly bits.
  • 47:15 - 47:20
    You can make faster changes, because you've used a template to define everything.
  • 47:20 - 47:24
    If you need to make an update, often you can just go change a template and...
  • 47:24 - 47:26
    Bang! The whole model changes.
  • 47:26 - 47:30
    Rather than trying to search and replace through each place that you used, string 25.
  • 47:30 - 47:34
    Try and find it and change it to string 30.
  • 47:34 - 47:38
    Better consistency, because you don't have a bunch of different people.
  • 47:38 - 47:40
    If someone goes, "Oh Boolean," those are ints.
  • 47:40 - 47:42
    "Oh Boolean," that's a Char 1.
  • 47:42 - 47:44
    "Oh Boolean," that's a Varchar 5.
  • 47:44 - 47:46
    You're just picking the Boolean templates.
  • 47:46 - 47:52
    You have much better consistency across your model, consistency in string lengths.
  • 47:52 - 47:57
    A big one for me, this is the reason I got into it, database independence.
  • 47:57 - 48:00
    You define different prototypes for different databases.
  • 48:00 - 48:02
    It's very easy to switch between them.
  • 48:02 - 48:06
    On the project I'm working on now, we've got a CIO who says,
  • 48:06 - 48:11
    "I really want you to stick to the corporate standard of Microsoft SQL server,"
  • 48:11 - 48:14
    which really sucks, by the way!
  • 48:14 - 48:18
    We want to use FrontBase, because it doesn't suck!
  • 48:18 - 48:21
    In order to keep them happy, every night we have this whole bank of tests.
  • 48:21 - 48:25
    We run it against Frontbase. I flip the prototypes,
  • 48:25 - 48:28
    and then we run it against it against SQL server.
  • 48:28 - 48:33
    That's with one little configuration change and there you go! Use the prototypes.
  • 48:33 - 48:37
    - And also, any Entity Modeler is specifically designed for use with prototypes.
  • 48:37 - 48:41
    If you find Entity Modeler is annoying to use, it's because you're not using prototypes.
  • 48:42 - 48:46
    There may be other reason, too. Don't get me wrong. But that one in particular.
  • 48:46 - 48:49
    - Yes.
    Pardon?
  • 48:52 - 48:54
    - Like the DVDs?
  • 48:57 - 48:59
    - Do you mean, how to do it?
  • 49:16 - 49:18
    - It's in Wonder, of course.
  • 49:18 - 49:23
    - ER prototypes in Wonder.
    - Yeah. ER prototypes, there's a description of it in practical Web Objects.
  • 49:23 - 49:26
    If I recall correctly, there's stuff in the Wiki as well.
  • 49:26 - 49:37
    - It's also in the old EO model of documentation PDFs.
  • 49:41 - 49:46
    Actually, using EO prototype has been part of object since the beginning.
  • 49:46 - 49:52
    It has always been the best practice. It's never changed in 12 years.
  • 49:52 - 49:59
    - A long time ago, not too many people did this.
    People are slowly learning.
  • 50:00 - 50:06
    - Just to be fair, prototypes were mostly brought in as the latest fashion of EO,
  • 50:06 - 50:10
    just before it was replaced by the awesome tool that Mike wrote.
  • 50:12 - 50:19
    That's why most of the people didn't use them, but they were part of the WO specification from the beginning.
  • 50:20 - 50:25
    - Again, use EO prototypes. If you are, well you know what's wrong.
  • 50:25 - 50:32
    - We actually reengineered them for 5.2. They're now extremely reliable.
  • 50:32 - 50:36
    They've got some really nice cool stuff that you can do with prototype,
  • 50:36 - 50:40
    so really I encourage you to go and have a look.
  • 50:40 - 50:44
    - You heard it from Pierre.
    - Except for the bug report I just filed.
  • 51:08 - 51:09
    Yeah. That's a good point.
  • 51:09 - 51:11
    There really is not a single place for this that has all the layers.
  • 51:11 - 51:15
    - You're book talks about it, but not...
    - It's outdated, yeah.
  • 51:16 - 51:19
    - The concepts are definitely...
  • 51:19 - 51:21
    - The concepts are the same, but the screenshots would be wrong
  • 51:21 - 51:24
    - ...the screenshots would be wrong, basically.
  • 51:27 - 51:29
    - One of these days, maybe.
  • 51:29 - 51:32
    Let me know when you finish it.
  • 51:33 - 51:38
    That's probably a good point. Something, somebody should write something about it.
  • 51:40 - 51:44
    If anybody reminds me, maybe I'll do it. Otherwise, I'll forget it.
  • 51:45 - 51:49
    - Yeah. We're not done yet.
    - He's got one.
  • 51:49 - 51:53
    - He's got a book on the shelf, like waiting to go!
  • 51:54 - 51:59
    - I might add something to the WebObjects Wiki on Object style.
  • 51:59 - 52:02
    I can copy a chapter of our class book.
  • 52:02 - 52:11
    Then we have some central one‑step place to go to read about the prototypes.
  • 52:11 - 52:13
    - That'll be great! Thanks!
  • 52:13 - 52:18
    - Jeter wrote the class book on the big nerd ranche's Web Objects training sessions, just for background.
  • 52:19 - 52:22
    - Gave a course along with it, now.
  • 52:24 - 52:26
    What month is it now?
    June.
  • 52:29 - 52:32
    Moving on, on our EOF thing, monitor the SQL.
  • 52:32 - 52:36
    The great thing about web objects is you don't really have to think about the SQL.
  • 52:36 - 52:39
    You make your model, you make your Java,
    SQL takes care of itself.
  • 52:39 - 52:44
    But forgetting about the SQL entirely is at your own peril
  • 52:44 - 52:48
    because as you showed this morning, if you are not watching but the apps dumping out,
  • 52:48 - 52:52
    you can run into some pretty serious problems.
  • 52:52 - 52:55
    In order to see the SQL your application is generating,
  • 52:55 - 52:59
    you just launch it with that simple parameter,
  • 52:59 - 53:02
    and in your log you'll see all kinds of SQL.
  • 53:02 - 53:06
    I'd advise you at least some of the time when you are working,
  • 53:06 - 53:10
    have this on and actually look at what it's generating.
  • 53:10 - 53:15
    If you have it on, you don't actually look, it doesn't really do all that much good.
  • 53:15 - 53:18
    It slows your app down a little bit.
  • 53:18 - 53:21
    When you look into this SQL, what are you looking for?
  • 53:21 - 53:25
    One of the things you're looking for is repeated single row selects.
  • 53:25 - 53:27
    Select from customer. Select from customer.
  • 53:27 - 53:30
    Select from customer. Select from customer.
    Select from customer.
  • 53:30 - 53:32
    Because if you're seeing it doing that,
  • 53:32 - 53:36
    then you're probably needing either batch faulting in your model,
  • 53:36 - 53:39
    which you can see over here on the right down at the bottom.
  • 53:39 - 53:41
    Set the batch faulting in size in the advanced tab.
  • 53:41 - 53:44
    The default is one, which again,
  • 53:44 - 53:49
    I said before, some of the defaults and WebObjects, one isn't really very useful.
  • 53:49 - 53:53
    Even if it's two, you'll get half the number of fetches.
  • 53:56 - 53:59
    Probably for most apps, for most relationships,
  • 53:59 - 54:02
    you want something a little bit bigger than one.
  • 54:04 - 54:07
    When that doesn't work, or that's not doing it for you,
  • 54:07 - 54:10
    there's this really cool class in Wonder,
  • 54:10 - 54:15
    that you really want along with your XQ, called ERX recursive batch fetching.
  • 54:15 - 54:17
    Worst name ever.
  • 54:17 - 54:19
    - But a great class.
    - But a great class.
  • 54:19 - 54:22
    - I've fallen in love with this over the last year or so.
  • 54:22 - 54:28
    It's really good for optimization of fetches. I've run into a few odd problems,
  • 54:28 - 54:29
    mostly with SQL Server,
  • 54:29 - 54:33
    and pre‑fetching, and some weird inheritance things
  • 54:33 - 54:36
    where it doesn't work, that class does.
  • 54:36 - 54:38
    That's another reason to look at it.
  • 54:38 - 54:41
    I got to talk to you about that later.
  • 54:43 - 54:46
    The other thing you're looking for besides single row selects are slow queries.
  • 54:46 - 54:48
    Something that's taking too long.
  • 54:49 - 54:53
    Too long being a relative term for how much data you have in the database,
  • 54:53 - 54:56
    how much data you expect in the database.
  • 54:56 - 55:00
    If you've got slow queries, one of the things you can use is,
  • 55:00 - 55:03
    again from Wonder, it's full of all these neat little tools.
  • 55:03 - 55:08
    Again, you don't need to marry it. You can just see it on the side.
  • 55:08 - 55:14
    ERX adapter channel delegate, you can turn that on and it'll log out queries.
  • 55:14 - 55:20
    It will log out, you can say, "OK, any query that takes longer than 200 milliseconds,
  • 55:20 - 55:23
    I want to see that. Any query that takes longer than a second, I want to see that."
  • 55:23 - 55:26
    You can do some other fine tuning. I forget, like,
  • 55:26 - 55:28
    "I only want to see queries in this entity name."
  • 55:28 - 55:34
    But it's a good way to find out what in your app's taking longer than you really want it to.
  • 55:34 - 55:39
    The usual answer to that is your missing indexes.
  • 55:39 - 55:43
    Usually you can make the query fast enough by adding indexes.
  • 55:43 - 55:49
    A few times, I've found that you can't, just whatever the SQL is, the database just doesn't optimize it correctly.
  • 55:49 - 55:55
    The thing to try then is some of Pierre Bernard's qualifiers from the HOW‑TO frame works,
  • 55:55 - 55:57
    or some of the qualifiers from Wonder,
  • 55:57 - 56:01
    some crossover between them and often by qualifying it differently,
  • 56:01 - 56:03
    you can get it to generate different SQL.
  • 56:03 - 56:08
    I've seen it go, like, from 40 seconds to a quarter of a second,
  • 56:08 - 56:11
    just by using a different qualifier, same result.
  • 56:16 - 56:19
    - OK. Index, it's really, really useful.
  • 56:19 - 56:23
    Nowadays you can actually define them in your model.
    So...
  • 56:23 - 56:25
    Use it.
  • 56:25 - 56:32
    - As a 5.4.
    - In 5.4 Yeah, and in [indecipherable] , too.
  • 56:32 - 56:36
    It's supported, it's you can do it directly from the UI.
  • 56:36 - 56:43
    You just define it, it's going to generate a proper SQL and so it's really easy to use.
  • 56:43 - 56:46
    Just put the index in the model.
  • 56:46 - 56:50
    - Yeah, when 5.42 comes out which should be really soon now...
  • 56:50 - 56:52
    - We hope.
  • 56:52 - 56:55
    - This is going to be a great feature. I'm really looking forward to that one.
  • 56:55 - 56:56
    - It's actually been in 5.4 since zero,
  • 56:56 - 57:03
    but because Entity Modeler uses the 5.3 APIs it didn't work quite right for me until 5.4.
  • 57:03 - 57:04
    - Can I just add to that for a sec?
  • 57:04 - 57:06
    Put on a database hat for a minute.
  • 57:06 - 57:08
    As somebody pointed out in the audience,
  • 57:08 - 57:13
    it does make sometimes not so much sense to add too many indexes.
  • 57:13 - 57:16
    Testing, testing with large data sets.
  • 57:16 - 57:19
    Testing your queries and seeing how they run, finding,
  • 57:19 - 57:25
    if you don't have the experience yourself to look at the database, get someone who does.
  • 57:25 - 57:28
    I had a very interesting production environment.
  • 57:28 - 57:32
    The database house was owned totally separate from the app side.
  • 57:32 - 57:34
    The database side was like,
  • 57:34 - 57:38
    "Oh, yeah, you run that query. You asked us to profile it. It runs in three seconds."
  • 57:38 - 57:41
    The app guys are saying it's the database guys,
  • 57:41 - 57:44
    and the database guys are saying it's the app guys.
  • 57:44 - 57:46
    They're having this great fight.
  • 57:46 - 57:48
    I managed to have a look at it. Yeah, it's true.
  • 57:48 - 57:51
    That single query runs in three seconds, no problem.
  • 57:51 - 57:57
    Except that the app guys don't realize that a single user instance of a click,
  • 57:57 - 58:03
    someone in a browser, initiates 3000 of those fetches.
  • 58:07 - 58:09
    The app has this little bit of trouble.
  • 58:09 - 58:12
    Yeah, profile. Check out what's going on.
  • 58:12 - 58:17
    Watch your logs, and test it and see what happens.
  • 58:18 - 58:20
    - Thanks.
  • 58:23 - 58:27
    - If you're using Oracle, watch out for everything.
  • 58:27 - 58:30
    -I was going to say, stay away from Oracle.
  • 58:30 - 58:33
    - I disagree. I grew up on Oracle
  • 58:33 - 58:38
    from Oracle four on, and there are some really awesome features in Oracle.
  • 58:38 - 58:40
    - That's so sad.
  • 58:40 - 58:45
    - It would take those 3000 queries and actually work whereas mostly [indecipherable]
  • 58:45 - 58:46
    - Oh yeah, no, no, no, no.
  • 58:46 - 58:53
    The 3000 queries was, in fact, Oracle, and it did, in fact, work just fine eventually.
  • 58:53 - 58:58
    - 9000 seconds later.
    - It just took a while to run, no problem.
  • 58:58 - 59:04
    - Are you saying qualifying the dates or indexing the dates or both out of curiosity?
  • 59:04 - 59:06
    All of the above?
  • 59:13 - 59:15
    Oracle dates, time stamps.
  • 59:17 - 59:24
    Sequel, JBC when you're using a NS timestamp will output a Java sequel timestamp.
  • 59:24 - 59:26
    If you have your Oracle column set to date,
  • 59:26 - 59:31
    Oracle then in the database has to convert that Java sequel time stamp into a date.
  • 59:31 - 59:34
    If you've used that date, say as a partition column,
  • 59:34 - 59:38
    you're going to have a query that takes 100 to 200 times longer to execute than
  • 59:38 - 59:42
    if you had just passed in a time stamp, or if you used a time stamp for your partition column.
  • 59:42 - 59:45
    There's a nice work‑around.
  • 59:45 - 59:48
    I'm not sure if there's a techno publish for it.
  • 59:48 - 59:51
    We discovered it last year at WOWODC.
  • 59:51 - 59:56
    It's basically telling Oracle to work in the 8I mode.
  • 59:56 - 59:59
    You lose all your 10G features.
  • 60:04 - 60:08
    OK, next one I'll go through pretty quickly. Awake from insertion,
  • 60:08 - 60:09
    it's the EO constructor.
  • 60:09 - 60:13
    If any of you have ever tried to use the actual Java constructer in your enterprise objects
  • 60:13 - 60:17
    you probably quickly discovered that wasn't really a good thing to do.
  • 60:18 - 60:21
    If you want to do your initialization in awakeFromInsertion,
  • 60:21 - 60:25
    it's the place to set defaults for your enterprise objects.
  • 60:25 - 60:31
    The little known fact that I want to point out today is that it can get called more than once.
  • 60:32 - 60:36
    Two cases have been pointed out recently, Java client
  • 60:36 - 60:40
    and nested editing context can result in this getting called more than once.
  • 60:41 - 60:43
    In order to protect yourself
  • 60:43 - 60:49
    the best practice is to check to make sure a value is null before you set the default.
  • 60:49 - 60:53
    If not, then probably something else has been done with that object
  • 60:53 - 60:55
    and you don't want to go back to the default.
  • 61:16 - 61:21
    - There is also the init method you can override if you're using Wonder
  • 61:21 - 61:25
    which checks whether it's a temporary global ID or not.
  • 61:25 - 61:29
    If you deleted an object from an editing context
  • 61:29 - 61:32
    and do an undo on the editing context it gets reinserted.
  • 61:32 - 61:35
    - Oh, that's another good point, yeah.
    - You want to set up the default values there.
  • 61:35 - 61:42
    Use in it or check whether the global id is a temporary global ID or a non temporary.
  • 61:50 - 61:54
    - OK, now a few quick Java ones, exception handling.
  • 61:55 - 61:57
    Don't do this.
  • 61:57 - 62:00
    How many times have I seen code...
  • 62:14 - 62:16
    I thought somebody would like that.
  • 62:18 - 62:22
    Don't write code like that.
    Just don't do it.
  • 62:22 - 62:23
    I've seen so many people do that and it's just,
  • 62:23 - 62:25
    "Oh, it will never happen. Don't worry about it."
  • 62:25 - 62:27
    Sooner or later, yeah, it does happen.
  • 62:27 - 62:30
    - What if you expect it and it won't hurt?
  • 62:37 - 62:42
    - Whatever you want to do in the privacy of your own application is fine with me.
  • 62:42 - 62:44
    - He's right. That does occasionally happen.
  • 62:44 - 62:48
    For me when that happens I always put a comment in that catch,
  • 62:48 - 62:50
    and explain why I'm doing that.
  • 62:50 - 62:53
    Because someone is going to come back behind you and wonder...
  • 62:53 - 62:55
    they'll think you're a bad programmer.
  • 62:55 - 62:57
    - Yeah. On the very rare occasions when you expect it
  • 62:57 - 62:59
    and it won't hurt and you're dealing with it some other way,
  • 62:59 - 63:03
    then, yeah, just comment it. But don't leave an empty block like that.
  • 63:05 - 63:09
    The problem is, though, if you don't have that in there then you have to say,
  • 63:09 - 63:11
    "OK, this method throws parse exception."
  • 63:11 - 63:14
    Then all the methods that call that have to throw parse exception.
  • 63:14 - 63:16
    You end up making changes all over your code.
  • 63:16 - 63:19
    It's a real irritation of Java checked exceptions.
  • 63:19 - 63:23
    The best practice for this, instead of swallowing the exception,
  • 63:23 - 63:26
    convert it to unchecked and re throw it.
  • 63:26 - 63:30
    - Or throw it. Or throw the original.
  • 63:30 - 63:32
    - Yeah, but if it's checked then you have to declare it all the time. - Yes.
  • 63:32 - 63:35
    - As opposed to...
  • 63:35 - 63:37
    nobody likes to do that. Nobody is going to do that.
  • 63:37 - 63:40
    Nobody is going to make that many changes in their code.
  • 63:40 - 63:45
    This forward exception has a little bit of a private API call that you can use there
  • 63:45 - 63:49
    if you want to stick with that. Pierre is shaking his head going no,
  • 63:49 - 63:51
    and I agree with Pierre because I don't do that.
  • 63:51 - 63:54
    - I hate that feature of Web Object.
  • 63:54 - 63:57
    It's forward exception is something that...
  • 63:57 - 64:01
    objective C polluting Java, it's...
  • 64:02 - 64:06
    - I get this from Wonder, and I blame Wonder for making me do that.
  • 64:06 - 64:10
    I did it the nice way and Anyo got cranky at me.
  • 64:12 - 64:14
    There's actually a class called Exception Converter.
  • 64:14 - 64:20
    In the notes to the slide there's a URL for it, and it's a much nicer thing to do.
  • 64:20 - 64:23
    - Well, you run that exception?
  • 64:23 - 64:27
    - Yes, but the problem of throwing in a run time exception is you lose the original stack trace.
  • 64:27 - 64:30
    - You chain it, you chain it.
    - Not if you put parentheses E.
  • 64:30 - 64:36
    - Yes. Actually parentheses E plus exclusion as to what in this level why it's being thrown.
  • 64:36 - 64:40
    - Chain, chain, chain always chain.
    - No.
  • 64:45 - 64:48
    - I would say definitely and the most important is to throw.
  • 64:48 - 64:52
    Beyond that your personal religious beliefs on
  • 64:52 - 64:56
    throwing checked or not or changing or not, are less important,
  • 64:56 - 64:59
    but not swallowing it the really important thing.
  • 65:01 - 65:03
    - OK, at least we can agree on that much.
  • 65:03 - 65:06
    The rest of it is just a quite good practice.
  • 65:09 - 65:11
    Use formatters.
  • 65:12 - 65:14
    A lot of people seem to be afraid of these.
  • 65:14 - 65:16
    I ended up using them all the time.
  • 65:16 - 65:17
    They're easy to write.
  • 65:17 - 65:22
    If you look at the whole API for, was is Java text format,
  • 65:22 - 65:24
    there's a whole lot of stuff there. But,
  • 65:24 - 65:26
    with Web Objects, you usually don't care.
  • 65:26 - 65:28
    You're formatting one value of an input,
  • 65:28 - 65:34
    and you're...you're parsing one value of an input or you're formatting it into a string.
  • 65:34 - 65:39
    You don't need to get too carried with writing fancy, fancy formatters.
  • 65:39 - 65:43
    It's good because it keeps the views separate from the model and the controller.
  • 65:43 - 65:47
    Rather than using a formatter, you can often just do it in a WO component.
  • 65:47 - 65:51
    The thing is that this is a little bit smaller than a WO component.
  • 65:51 - 65:54
    It's easier to reuse across a bunch of WO components.
  • 65:55 - 65:58
    It promotes reuse because of that.
  • 65:58 - 66:02
    The code's not tied to one specific page.
    Yes?
  • 66:19 - 66:21
    - This is going to get ugly
  • 66:21 - 66:23
    A lot of the formatters aren't thread‑safe.
  • 66:23 - 66:26
    I think all the ones I rate are thread‑safe.
  • 66:26 - 66:31
    But, I know some of the Java timestamp formatters, and some of the other ones aren't thread safe.
  • 66:31 - 66:34
    The best practice is probably to cache them in a session
  • 66:34 - 66:36
    if you're not going to get multiple requests,
  • 66:36 - 66:38
    unless of course, you're using a long response page
  • 66:38 - 66:40
    in which case then you've got a different problem.
  • 66:42 - 66:45
    The best practice is, it depends but think about thread safety.
  • 66:45 - 66:49
    - Yes. None of the Java formats are as thread‑safe.
  • 66:50 - 66:55
    - Sorry. It's actually not that costly to pick a formatter.
  • 66:55 - 67:02
    Just don't try to share a formatter between threads. You're asking for trouble.
  • 67:03 - 67:07
    There's no doubt, I put the date and time into the session
  • 67:07 - 67:09
    as seen from the slides to hold the time zone in them?
  • 67:09 - 67:13
    But the rest of them I just make on the fly because they usually don't have any data in them.
  • 67:15 - 67:20
    - Also Wonder Helper functions.
    - Wonder Helper functions?
  • 67:21 - 67:22
    - Nice.
  • 67:26 - 67:30
    Just a couple of quick examples on how to write very simple formatters.
  • 67:30 - 67:36
    This one here just takes an NSArray and
  • 67:36 - 67:38
    puts it with a bunch of page breaks between it.
  • 67:38 - 67:41
    You can easily deal with a little WORepetition and a string,
  • 67:41 - 67:44
    but then you've got another component with a WORepetition and String
  • 67:44 - 67:50
    or you've got part of your component that is less reusable than it could be because it's inside of it.
  • 67:51 - 67:55
    That "return buffer.append" in the format command
  • 67:55 - 68:00
    is the entire implementation of the formatter,
  • 68:00 - 68:03
    and it's not particularly difficult.
  • 68:03 - 68:08
    We're not going to bother parsing this so I just throw an exception.
  • 68:08 - 68:13
    But, those are the only two methods you actually have to implement to make a formatter.
  • 68:13 - 68:18
    If you're doing output only, it can be as simple as one line long.
  • 68:18 - 68:21
    A little bit more complex example.
  • 68:21 - 68:25
    This one here converts between separators in a string.
  • 68:25 - 68:27
    I'm working on a system now as a bunch of legacy stuff,
  • 68:27 - 68:30
    and some things are comma separated and some things are tab separated.
  • 68:30 - 68:35
    I use a formatter to move things back and forth.
  • 68:35 - 68:36
    You can also do the same thing
  • 68:36 - 68:40
    if you've got a string of text that somebody's typed in a text box
  • 68:40 - 68:43
    and you want to format it out in HTML to keep the page breaks,
  • 68:43 - 68:45
    it'll do that.
  • 68:45 - 68:48
    If you've got a bunch of HTML like from an XML file
  • 68:48 - 68:50
    or something and you want to convert it back into a paragraph, it'll do that.
  • 68:50 - 68:55
    Again, there's really only two lines in it that do anything.
  • 68:55 - 69:01
    The format one just does, just calls a replace along the string from the internal to the external.
  • 69:01 - 69:04
    The parsing just changes it backwards.
  • 69:04 - 69:05
    That's all you need to do.
  • 69:05 - 69:08
    The only thing special, if you notice the first line in the parsed object,
  • 69:08 - 69:11
    it was position set indexed string length.
  • 69:11 - 69:13
    You just have to set it to something.
  • 69:13 - 69:17
    If you leave it at zero, Java will throw an exception for you.
  • 69:17 - 69:20
    Just set it at something, keep Java happy.
  • 69:20 - 69:25
    There you go. Formats and parses, there's only really two lines of code.
  • 69:26 - 69:30
    If you start using them, you'll find all kinds of places you can use them.
  • 69:30 - 69:35
    I like them a lot.
    No comments?
  • 69:37 - 69:42
    - Position set index can be or even important if you're chaining format is to give one
  • 69:42 - 69:44
    inside the other because you don't know where you're
  • 69:44 - 69:47
    starting and ending in the paths for the next one.
  • 69:47 - 69:51
    - Yes, but usually I try to keep them fairly simple.
  • 69:51 - 69:53
    Yes, if you're trying to do like a full blown formatter,
  • 69:53 - 69:56
    then you actually do need to worry about the position.
  • 69:56 - 69:58
    - The point of the Wonder Helpers, by the way, is
  • 69:58 - 70:02
    that formatters you can only...well, from the binding, from binding,
  • 70:02 - 70:07
    you can only use them on components that expose a formatter finding.
  • 70:07 - 70:10
    Wonder Helpers you can use on any binding.
  • 70:10 - 70:13
    - That's nice.
    - I don't think I've used those.
  • 70:13 - 70:16
    - You should because you steal them.
    - I will.
  • 70:19 - 70:22
    - Right, right. You can have multiple...
  • 70:24 - 70:27
    - They can be extended into something else.
  • 70:28 - 70:31
    - I usually just chain the formatter instances.
  • 70:32 - 70:35
    - No instances.
    - We won't go there.
  • 70:35 - 70:40
    OK, so, moving on to our final topic, I think we're, are we out of time Pascal, or Keep going.?
  • 70:40 - 70:44
    Deployment, trying to get through here quickly.
  • 70:44 - 70:47
    There's really not much to say about deployment that hasn't been said in other places.
  • 70:47 - 70:52
    Manage dependencies, plan for change. It's going to happen.
  • 70:54 - 70:58
    Web Object extensions directory sounded like a great idea when it first came out,
  • 70:58 - 71:00
    jammed all kinds of jars in there. It was wonderful.
  • 71:00 - 71:06
    Then I needed to update one app in the server and I couldn't update the other apps and it was terrible.
  • 71:06 - 71:11
    For deployment, my advice is just delete everything in that directory.
  • 71:13 - 71:16
    It's just a dependency nightmare waiting to happen.
  • 71:16 - 71:20
    Instead, if you need it, if you need jar files,
  • 71:20 - 71:23
    put them in a framework, use the framework in your application.
  • 71:23 - 71:26
    Framework goes into your subversion repository wherever your repository is.
  • 71:26 - 71:29
    Manage the dependencies like that.
  • 71:30 - 71:32
    In fact, I'll go one further and say,
  • 71:32 - 71:34
    "You should embed all frameworks."
  • 71:34 - 71:38
    All frameworks, I include the Web Objects ones as well
  • 71:38 - 71:43
    because that way you can deploy applications using different versions of Web Objects,
  • 71:43 - 71:46
    different versions of the jars on the same server.
  • 71:46 - 71:47
    You don't have to worry about conflicts.
  • 71:47 - 71:49
    And Yeah, people are going to say,
  • 71:49 - 71:52
    "Oh, it's going to be bigger. Oh, no."
  • 71:52 - 71:58
    I'll happily trade off some FDP upload time for manage dependencies.
  • 71:58 - 72:01
    - OK. Two comments on that.
  • 72:01 - 72:03
    Most embedding framework,
  • 72:03 - 72:06
    I would encourage you to embed a jar version of the frameworks.
  • 72:06 - 72:12
    If you look at since 5.2, I think.
  • 72:15 - 72:17
    You can actually jar your framework,
  • 72:17 - 72:20
    and they would work just the same.
  • 72:20 - 72:24
    You can just dump them in your application in content extensions,
  • 72:24 - 72:29
    and they're going to get loaded exactly like any other framework.
  • 72:29 - 72:32
    It's very compact, it works really well.
  • 72:32 - 72:35
    You cannot [indecipherable] jar.
  • 72:35 - 72:43
    You can have flat jars which are the same.
  • 72:43 - 72:47
    The other comment that I would say on the size of the app,
  • 72:47 - 72:53
    is that gziped your app, before you upload them, you will save more time.
  • 72:55 - 73:01
    It's incredible, I have seen so many people trying to upload a .woa not zipped.
  • 73:01 - 73:07
    It takes forever because the protocol are usually very inefficient on starting and stopping files.
  • 73:07 - 73:13
    You are going to upload hundreds of small, tiny files, which is crazy.
  • 73:13 - 73:14
    - Yes
  • 73:14 - 73:22
    - gzip's them, you'll be surprised you can save one, if not two order of magnitude in the upload.
  • 73:25 - 73:29
    - If I can continue with that, once you have zipped it and put it up once,
  • 73:29 - 73:34
    use RSync to sync it after that, because then you only move differences.
  • 73:34 - 73:36
    - Don't do that.
  • 73:40 - 73:45
    The reason you should not do that is because you will have a running app on the old version.
  • 73:45 - 73:46
    If you have multiple instances,
  • 73:46 - 73:52
    you really should upload it into a different folder and do a version swap so you have...
  • 73:52 - 73:57
    - To be clear, you should shut down the production site prior...
  • 73:57 - 73:59
    - No, no. You don't want to shut down the production site.
  • 73:59 - 74:00
    You want to keep it running.
  • 74:00 - 74:03
    - You just Rsynching the zip file, not the app.
  • 74:03 - 74:06
    - Then you have to unzip it on the server.
    - No, you're proposing unzipping the WOA, I think.
  • 74:06 - 74:10
    - I was Rsynching the WOA, right? But I shut down the site.
  • 74:10 - 74:15
    - If you don't want to shut down your production site
  • 74:15 - 74:19
    and you don't want to be replacing your WOA in line.
    - Yes.
  • 74:19 - 74:22
    - Especially because Java catches jar index offsets.
  • 74:22 - 74:27
    - If you replace a jar in a running app....
    - Things get very, very interesting.
  • 74:27 - 74:29
    - ..you get horrible, horrible problems.
  • 74:29 - 74:35
    - If you try to load a component that hasn't been loaded yet, the jar offset is wrong
  • 74:35 - 74:38
    so it will just give you a bizarre "no class.found" error.
  • 74:38 - 74:45
    It's a bad error. It's bad. That is all.
  • 74:49 - 74:51
    - Because I noticed it the other day and because I think it's great,
  • 74:51 - 74:59
    when you look at 5.4, they now ship examples in a format where you build ANT
  • 74:59 - 75:07
    and you get legacy, JAR, and WAR versions fully embedded of all the examples from Web Objects
  • 75:07 - 75:10
    If you don't know how these work or you don't know how to build them,
  • 75:10 - 75:16
    they ship with 5.4 examples now. Thanks, Pierre and whoever else made that happen.
  • 75:16 - 75:18
    - It was actually Daryl.
  • 75:18 - 75:21
    - OK. Thanks Daryl.
    - Thanks Daryl.
  • 75:23 - 75:26
    - Is that a hand in the air?
  • 75:28 - 75:31
    - He may have been the shadow we run to the door.
  • 75:33 - 75:35
    - I just have a quick question for Pierre.
  • 75:35 - 75:38
    When you compile those jars into the extension directory,
  • 75:38 - 75:43
    [indecipherable] and you still have to put them back in the [indecipherable], correct?
  • 75:43 - 75:45
    - No.
  • 75:45 - 75:56
    - If you just shovel them in there then you're lost when the application starts?
  • 75:56 - 76:01
    - Any jars in your slash content extension
  • 76:01 - 76:06
    are going to be loaded before anything else in your class paths.
  • 76:06 - 76:08
    There is nothing you have to do.
  • 76:08 - 76:11
    It's even loaded before the library extension.
  • 76:11 - 76:18
    If you want to override a JAR, you just put it there.
  • 76:18 - 76:22
    It's going to be loaded before anything else.
  • 76:25 - 76:28
    - OK. I just want to go through one quick final topic here,
  • 76:28 - 76:34
    and we're running low on time. Don't repeat yourself really.
  • 76:38 - 76:42
    I've only got so many jokes. I have to use the lame ones.
  • 76:43 - 76:46
    One of the things that bothered me when I first started using WOlips
  • 76:46 - 76:48
    is I had all these build files for each project,
  • 76:48 - 76:50
    and they were all substantially the same.
  • 76:50 - 76:52
    I always had to go in there and fiddle them.
  • 76:52 - 76:55
    Then another version of WOlips would come out, and I'd have to change the things again.
  • 76:55 - 77:03
    In ANT 1.6 they added the ability to import one build.xml file into another.
  • 77:03 - 77:06
    That's a really good thing to do.
  • 77:06 - 77:11
    For an example of doing things like that, see the Wonder build system.
  • 77:11 - 77:17
    It is really quite complex, but you can find a lot of interesting things in there.
  • 77:17 - 77:20
    I'm currently redoing our build system
  • 77:20 - 77:24
    so that I have a couple of shared files that all the projects use.
  • 77:24 - 77:30
    This is what I've ended up for a build file for a WO framework.
  • 77:32 - 77:37
    That's it, three lines and a couple properties. It's a lot easier to maintain.
  • 77:37 - 77:39
    - OK. Just one comment on that.
  • 77:39 - 77:45
    Look at Maven. You can actually build some awesome tools with Maven.
  • 77:45 - 77:49
    I think there was a demonstration last year from Jake.
  • 77:51 - 77:55
    Maven is actually an extremely good tool to build Web Objects.
  • 77:55 - 77:58
    That's how we build Web Object every night.
  • 77:58 - 78:03
    We use Maven. We've got a Maven build system for Web Objects.
  • 78:05 - 78:09
    It's really awesome. It takes care of all the dependency.
  • 78:09 - 78:16
    It's really reliable, in fact, you don't have to write much code if you accept two of the Maven conventions.
  • 78:19 - 78:20
    - I don't.
  • 78:23 - 78:25
    - We use some funky tools. You can ask Mike.
  • 78:25 - 78:27
    Every time I tell him one of them he goes, "Oh, I want to die."
  • 78:27 - 78:31
    Our build files are highly customized,
  • 78:31 - 78:34
    so I don't know how happy it would be with Maven,
  • 78:34 - 78:35
    but I'm not going to go there.
  • 78:35 - 78:39
    There was a question and answer here, I've been doing some questions. I'm going to skip over this.
  • 78:39 - 78:42
    We don't have time to go into the fun topics,
  • 78:42 - 78:46
    but if you want something to talk about over beer tonight...
  • 78:46 - 78:53
    - They're hard to read from this distance, and we'll take that as a good thing.
  • 78:54 - 78:57
    - It didn't look so bad on the screen. I was trying to find something
  • 78:57 - 79:01
    that didn't look quite so horrible. Just a second here.
  • 79:03 - 79:05
    Here, we'll just do this.
  • 79:11 - 79:13
    - Not much better.
  • 79:14 - 79:18
    - OK, OK. Everybody is a fricking art critic.
  • 79:24 - 79:30
    - If you wanted ugly discussions, this is the slide for you.
    - Hold that. I can't do this.
  • 79:30 - 79:34
    Oh, oh no.
  • 79:34 - 79:38
    This is like way more than my French can handle.
  • 79:38 - 79:42
    You can deal with the blue. I'm sorry.
  • 79:45 - 79:49
    I can read cereal boxes and soup cans but....
  • 79:57 - 80:00
    I decided it will be a fiery topic.
  • 80:00 - 80:02
    It makes spaghetti bindings.
  • 80:02 - 80:06
    - I use it a lot, but it still can make spaghetti bindings.
    - We validate that, by the way, now.
  • 80:06 - 80:10
    - [indecipherable] "bindings are spaghetti [indecipherable] "?
    - We validate.
  • 80:10 - 80:14
    Even the bindings part, oddball expression.
  • 80:14 - 80:18
    At least, it might be spaghetti, but we'll tell you if you have a bogus binding in the middle.
  • 80:18 - 80:21
    Personally, I like WOOgnl, we use it all the time.
  • 80:21 - 80:24
    But I've talked to some people who thought it was harmful.
  • 80:24 - 80:27
    - I feel bad every time I use it. But yeah, we use it, definitely.
  • 80:27 - 80:29
    - Just wash your hands afterwards, and everything will be fine.
  • 80:30 - 80:33
    Right? I think that's it. Thank you, everybody.
Title:
WebObjects Quite Good Practices
Video Language:
English

English subtitles

Revisions