Splitting the crud

Posted by jmls on 02-Mar-2011 01:09

ok, so now I am at a point where my basic code generator for table maintenance is nearly there. Given a table, it spits out the crud, valueobject and test unit classes. More importantly, it also preserves custom user changes in any previous version of the crud and valueobject.

I was just thinking of making the custom code a little easier and it crossed my mind to change the layout slightly.

Currently I have

/ValueObject/classname.cls

/lib/crud/classname.cls

/test/unittest/unit/classname.cls

the get / save / remove methods in the valueobject are placeholders for the code sitting in the crud class

What I was thinking of was

/ValueObject/classname.cls

/lib/crud/classname.cls

/lib/classname.cls

/test/unittest/unit/classname.cls

where /lib/classname.cls inherits the abstract /lib/crud/classname.cls. This /lib/classname.cls would only be created if the file doesn't already exist, and simply be a new class to inherit the /lib/crud/classname.cls. The get / save / remove methods in the valueobject are then placeholders for the code sitting in the /lib/classname.cls class

People can then add their own code to the /lib/classname.cls file without any loss when the classes are regenerated.

Am I on the right track here ?

All Replies

Posted by Peter Judge on 02-Mar-2011 07:48

jmls wrote:

ok, so now I am at a point where my basic code generator for table maintenance is nearly there. Given a table, it spits out the crud, valueobject and test unit classes. More importantly, it also preserves custom user changes in any previous version of the crud and valueobject.

I was just thinking of making the custom code a little easier and it crossed my mind to change the layout slightly.

Currently I have

/ValueObject/classname.cls

/lib/crud/classname.cls

/test/unittest/unit/classname.cls

the get / save / remove methods in the valueobject are placeholders for the code sitting in the crud class

What I was thinking of was

/ValueObject/classname.cls

/lib/crud/classname.cls

/lib/classname.cls

/test/unittest/unit/classname.cls

where /lib/classname.cls inherits the abstract /lib/crud/classname.cls. This /lib/classname.cls would only be created if the file doesn't already exist, and simply be a new class to inherit the /lib/crud/classname.cls. The get / save / remove methods in the valueobject are then placeholders for the code sitting in the /lib/classname.cls class

People can then add their own code to the /lib/classname.cls file without any loss when the classes are regenerated.

Am I on the right track here ?

I think so - I like the use of abstract methods for enforcing/ensuring the existence of methods in a derived class.

Relying on comments or annotations in the code as markers for code-here-or-not-here seems a little flaky to me (even though almost everyone uses it, including OEA for InitializeComponent) since there's no guarantee that some Code Dinosaur will blithley remove the "stuff I don't see the point of and that is cluttering up my code, man" and then you're up a certain creek without a paddle.

-- peter

Posted by jmls on 02-Mar-2011 10:19

so, if you wanted to extend the valueobject (custom properties etc),

would you create all of those as abstracts, and have another layer

above that inheriting the base value object ? (much like the thinking

behind extending the lib / crud stuff I was talking about).

also, how would you extend the before/after create/update/read/delete

parts of the crud library ? (for example , a calculated field, or

extra code to run before / after delete ) - create an override method,

do the calculation and then call the standard method ? Put a callback

in the crud method ? Raise an event ?

So many questions. So little time

Posted by rbf on 02-Mar-2011 10:57

Not sure about your architecture here, but I would *never* touch any of the generated code.

Instead always create a class that inherits from the generated code where you do your custom coding.

That way you can override whatever you want. The only code you ever have to look at (= maintain) is the custom class. The standard code can be regenerated at any time.

Even though we are not using a generator, we are always doing it this way in our generic environment. The factory checks if there is a custom class (based on a naming convention) and starts that if it exists, otherwise it starts the generic class (in your case: the generated class).

Works like a charm and we only see custom code. That IMHO is the only code we care about.

-peter

Posted by Thomas Mercer-Hursh on 02-Mar-2011 12:12

When I see something like this, my first reaction is to think in terms of the trouble one gets into from trying to do something without using the right tool.  By right tool I mean model to code translation ... no naming conventions to goof up, no markers to mispell, architecture configurable to need, etc.  Unfortunately, I don't have a working ABL MDA tool to hand you today.  You might, however, want to take a look at Phil Magnay's reverse engineering tool and consider what you could cobble together with EA generation of the shells, customization in OEA, and reverse engineering to move the custom code back into the model where it will get included in the next generation.  There is a lot suboptimum about this (look for a whitepaper soon), but it might give you a better foundation than trying to cobble something together on your own.

Absent that, I don't know exactly how you are doing your generation today, but I might consider something like my old Specification-Driven Development tool from the early 90s (no whitepaper, sorry).  This used a general purpose macro processor, templates, and specification files.  The templates had a lot of variations which could be selected by a simple note in the specification file.  This kept one from writing the same variations by hand over and over again.  Whenever I recognized that I was going to use a particular pattern more than a couple of times, I would add it to the options available in the template.  The templates also had hooks for genuinely custom code which one put in the specification file.  The result was the ability to regenerate at any time and yet to continue to evolve the templates so that, for example, a new feature could be added and one could simply run the generator on everything and have the new feature included everywhere.

Posted by Peter Judge on 02-Mar-2011 12:29

Julian said :

also, how would you extend the before/after create/update/read/delete

parts of the crud library ? (for example , a calculated field, or

extra code to run before / after delete ) - create an override method,

do the calculation and then call the standard method ? Put a callback

in the crud method ? Raise an event ?

This I'm not 100% about - still working through it myself, and I think it depends where you are in the stack, and how many other objects need to react (events vs. non-events), and what your design is (sorry :). If you have a general library that does most of the work, I'd think a callback would make sense for specialized behavior (ie don't customize the library). If there are multiple consumers, events make sense. My inclination is to override, since that's easier to read/understand, and then only the custom code appears in the derived object; but I do really think it depends.

-- peter

Posted by Thomas Mercer-Hursh on 02-Mar-2011 12:49

Oh, it occurs to me that I do have a slide deck on SDD.  It is more a marketing piece, but I would gladly send it to you if you were interested.

Posted by Admin on 02-Mar-2011 12:54

Oh, it occurs to me that I do have a slide deck on SDD.  It is more a marketing piece, but I would gladly send it to you if you were interested.

How about attaching it here?

Posted by Thomas Mercer-Hursh on 02-Mar-2011 13:13

It *is* 1992 era technology and, moreover, is rather more a marketing than a technical presentation, so I don't know that I would put it out there generally.  E.g., it isn't on my website and I don't even have a page on the website talking about SDD since it is yesterday's (and then some) technology.  But, I am happy to send it to individuals and talk about the ideas.  I would much rather point people to model to code translation, aka MDA, and will have some whitepapers on that soon.

This thread is closed