idea: configure Prolint rules by application layer

Project:Prolint Issue Tracker
Component:Miscellaneous
Category:feature request
Priority:normal
Assigned:Unassigned
Status:active
Description

Wouldn't it be nice when different rules apply to different application layers? For example: in an OERA application, you would specify that database-access is never allowed outside the DataAccess layer.

Implementing this idea would mean that layers (or components, etc) can be recognized. Probably by namespace or some other filename-pattern. Frankly I don't really like to rely on filename conventions, but I have no other idea. Someone else?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tamhas's picture

Rules by layer

It is a nice idea, but I despair of how to tell layer from layer except by naming conventions that I would find unacceptable. One might come up with a simple rule or two, like no UI in any module that also contains DB access, but I am skeptical of being able to tune this very finely. Note also that one has cases like domain objects which travel between layers.


We could never figure this

We could never figure this stuff out ourselves - so instead we built separate rulesets ... one for webspeed code, one for gui front-ends, etc ... not great but works.

As far as identifying things, I was thinking of treating anything that has a direct reference to a database and has no frame definitions as a server-side program, while something that has no database reference, but has frame definitions - as a client-side. Narrow, but probably would catch 95% of conditions on our side. Of course that requires a parse first to determine program type ...

In general though, I found that differentiation between rules is not important in our case. You can probably speed up the scan if you do not run needless rules, but its still safer than having a false decision on type of code.


jurjen's picture

Rules by layer

The usecase I was thinking about, is an OERA (or actually OESDK) appserver. It has business entities which are made up of at least two classes: one derived from the BusinessEntity class and one derived from the DataAccess class. The BusinessEntity child is supposed to have no database access at all.
But, since the BE child references the DA child, they both have to run in the same OpenEdge session which has to have a connection to the database. There does not seem to be a way to run or compile the BE layer with no databases connected, even if code in that layer does not access the database!!!

I have found that it is sometimes productive to write some FIND and FOR EACH stuff in the BE child, just to see if it produces the required results, and then refactor the db-access away to the DA child. Because it is productive, it is also dangerous: the danger is that you forget to refactor a bit, by accident or because you're in a hurry for a really quick fix and have no time to do it right.
And now I want Prolint to test this.


tamhas's picture

I get the usecase

I understand perfectly *why* you want to do it, but I don't see any way to do it without relying on a program naming convention which I abhor. The only other way that I can imagine would be adding a ProLint "hint" at the top which said which rules to apply.


jurjen's picture

Re: I get the usecase

Well, I believe a naming convention might not be so bad, when those conventions are configured by directory. While subdirectories inherit (and optionally override) the configurations from their parent directory. Something like how Apache parses .htaccess files, but without the geeky syntax.

That way, one could easily configure that everything matching "appserver/dataaccess/*" may have access to the database, and all other programs may not.

Implementation: the configuration files needed to configure this, must be located somewhere in the Prolint directory - not in the directory where the sources are that need to be inspected. That way they can be made read-only for regular programmers and read-write for Prolint configurators.

I wonder if it should be possible to configure this by profile or simply globally. Comments?


tamhas's picture

Naming

Naming convention by directory would do me no good since I put everything about Customer in com/cintegrity/IS/AR/Customer. I think that dividing the Customer stuff all over the place by presumed layer groups would make it much harder to look at Customer. Similarly, the prefix notation used in AutoEdge is bad, at least without breakdown into much finer directories, because it separates related programs/classes. The most I am willing to consider is some standard suffix naming conventions like CustomerFinder.cls or CustomerMapper.cls. But, even that is problematic for depending on this kind of parsing rule distinction, especially since I tend to use Customer.cls for the domain object.

While it doesn't help for large bodies of existing code, I can see that it might be acceptable to include a ProLint "hint" in a comment at the top of the file which indicated which ruleset(s) were to apply to it based on layer. Something like this could have a number of different applications. E.g., if one had a bunch of old ugly code that one knew one didn't have time to fix any time soon, one could indicate the use of a relaxed rule set which didn't nag so much, but when working on new code one could indicate the "strict" rule set to get the best possible code.


jurjen's picture

Re: Naming

> Naming convention by directory would do me no good since I put everything
> about Customer in com/cintegrity/IS/AR/Customer. I think that
> dividing the Customer stuff all over the place by presumed layer groups
> would make it much harder to look at Customer.

Yeah, that's certainly true. I have been wondering which would be more
convenient: directories for each layer/partition ("interface", "bl/be",
"bl/bt, "da" etc) or by entity. It both sucks, but I am still thinking
towards divisions by layer. Interesting discussion, but perhaps better to
continue somewhere in the OERA group.

> While it doesn't help for large bodies of existing code, I can see that it
> might be acceptable to include a ProLint "hint" in a comment at
> the top of the file which indicated which ruleset(s) were to apply to it
> based on layer.

Ok, but that would be a different feature request for a different
requirement :-)

What we really seem to need, is a way to have a rule-set by class (or
program type). But how?


tamhas's picture

Hinting

> Ok, but that would be a different feature request for a different
> requirement :-)

> What we really seem to need, is a way to have a rule-set by class (or
> program type). But how?

What I was attempting to suggest was that the hint indicate the class ... or classes, come to that. Thus, if the hint indicated that the type of program was data access, it would select rules which allowed database access and complained about UI, but if the hint indicated it was UI then it would do the reverse. If the hint indicated it was business logic, it would complain about both.

This could be used for a lot more than just layer-specific rules. The good news is that it is potentially a very powerful solution, but the bad news is that it requires one to edit the code to add the hints.


tamhas's picture

Naming Conventions

> Interesting discussion, but perhaps better to
> continue somewhere in the OERA group.

As much as I would like to expand the use of OE Hive, this seems like a topic which deserves a broader audience and, hopefully, the participation of the AutoEdge architects since they have actually published some documents on the topic, so I started a thread at PSDN.

http://www.psdn.com/library/thread.jspa?threadID=2738


tamhas's picture

Annotations

One possible implementation of the "hint" might be to use the OEA annotations, which would be a good indicator in any case of things like layer and type.


jurjen's picture

how about the inherited class?

> What I was attempting to suggest was that the hint indicate the class ...

In the meantime we have learned that Proparse can, for a given OOABL class file, determine the list of inherited classes (and implemented interfaces too, I suppose). So one possible rule could be that a class should not be allowed to access a database unless one of its ancestors is class "DataAccess". Where the string literal "DataAccess" should be configurable of course.
Is that an acceptable idea?


john's picture

interface

Interesting idea. One technique is to use an interface as nothing more than a flag on a class.

So you could have:
class Customer inherits whatever extends whatever, extends DataAccess ...

An alternative would be to have a special @prolint annotation on the CLASS statement to indicate that this class (and any subclasses) intentionally do data access.


tamhas's picture

Hints & Inheritance

If one implements a generalized feature in which a hint can indicate a particular rule set and also implements that, for classes, a hint in any ancestor class is equivalent to having the hint in the current class, then I think one would have a very powerful mechanism that required relatively little effort to implement. For .p code, one would still have to update every program, unfortunately, but anyone working with OO would be in great shape to take advantage of this.

I would make this entirely general purpose. I.e., the mechanism merely consists of logic such that, if the hint is present, then a particular block of rules is applied, otherwise it isn't. This can be used for the purpose which stimulated this discussion, but it could also be used for any other purpose, e.g., special rules to apply to programs containing socket code or webservices code or Sonic code, etc.

What would happen if there was a "conflict", e.g., a class ancestor says data access and a child says UI? I don't think I would report this as an error in itself, exactly because I think it is more powerful if we think of it in terms of attributes, of which multiple might apply to one file. I think this would resolve itself fast enough because the report would be full of both X is bad because this is DA and Y is bad because this is UI and it would be apparent that one had screwy hints.

Thus, one might have hints for UILayer, ChUI, GUI, and WUI and they are all different sets of rules.