We'll just code-gen our way out of here
First, we have the implementation of the SendPropertyChanged method, can you spot the bug?
protected virtual void SendPropertyChanged(String propertyName) { if ((this.PropertyChanged != null)) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }
Then, you have:
public string CustomerID { get { return this._CustomerID; } set { if ((this._CustomerID != value)) { this.OnCustomerIDChanging(value); this.SendPropertyChanging(); this._CustomerID = value; this.SendPropertyChanged("CustomerID"); this.OnCustomerIDChanged(); } } }
And this:
public Customer Customer { get { return this._Customer.Entity; } set { Customer previousValue = this._Customer.Entity; if (((previousValue != value) || (this._Customer.HasLoadedOrAssignedValue == false))) { this.SendPropertyChanging(); if ((previousValue != null)) { this._Customer.Entity = null; previousValue.Orders.Remove(this); } this._Customer.Entity = value; if ((value != null)) { value.Orders.Add(this); this._CustomerID = value.CustomerID; } else { this._CustomerID = default(string); } this.SendPropertyChanged("Customer"); } } }
Both properties show exactly why I despise code generation as an architectural approach.
Instead of taking the appropriate route, and actually solving the problem at hand, they just threw code at it until it looked like it worked.
Comments
thread safety comes to mind
I think this example corresponds to idea of code generation as bad code corresponds to the abstract idea of code.
I am biased, since I have done a lot of codegen (some of which was quite bad). But in general I do not see any method except codegen to be DRY and have SPOT. Of course, the generation may be quite limited (as you do with NHQG), and I actually prefer it to be limited.
And it can be considered an architectural approach, if the skeleton of your app is built upon your SPOT model (for example, NHibernate mappings may be used as a model).
Andrey,
Yes, it is bad code. Except that this is how most code gen solutions end up with.
SPOT?
For example, I generate mockable interfaces from the concrete classes (NRefactory-based build step) just because I despise manual code duplication no matter the reason.
SPOT = single point of truth
Andrey,
Yes, that is a path I am seriously considering now.
This just a lack of experience, same as for the hand-made code. I started with a similary bad code (in more subtle ways, OOP problems, etc), and then I moved it gradually to be better, not worse.
The thing I did not understood about codegen when I started was that the less generated code, the better. Ideally, the only reason why I am generating something should be to inject the facts of my model into the code. But even this may mean a lot of codegen in limited languages like SQL -- for example, my model supports custom primitive types with limits that are created as individual column checks in SQL Server.
Sorry for a lot of comments, Opera does not like this blog commenting system and I think too slowly. )
Andrey,
Do you know where those code samples came from?
No. My blind guess would be Entity Framework (I haven't looked on it yet).
Good guess, Linq for SQL
if i'm not mistaken that's dlinq
Code gen should be used as a computer aided way of typing code. So instead of you do the typing, a machine does it for you.
Saying that code-generation is bad is stupid, as it means that typing is bad. What should be said in THIS case is that what's generated isn't great. So the solution shouldn't be: "Oh I'll do it by hand" but: "Oh, I'll generate something better".
However, with the example at hand, you can't: it's not template based.
So code generation with templates, why is that bad exactly?Because it can do the typing faster than you and therefore a consultant who's payed by the hour earns less? ;)
Just a reminder: nhibernate uses code-generation as well, at runtime ;)
Frans,
No, it should not. You should find ways to avoid typing the code in the first place.
Irrelevant.
Because once you start with code gen, people seems to forget that generated code should fall under all the laws & rules of code anywhere.
I don't like this type of generated code either. I can possibly understand this type of code being generated by a 3rd party framework if there simply wasn't a better way, but that is not the case here with Linq to Sql and MS generated code. What do I mean? To me this is a perfect example of a case where MS should have realized this type of code is ugly and error prone and only necessary because another solution didn't exist -- and then being MS they should have actually solved the real problem for all of us so that this type of code is avoidable. Its a lot harder for the rest of us to take on the actual problem, which is why none of the existing AOP type solutions really work as well as we'd like, but this was a perfect opportunity for MS to take it on and solve it once and for all for us. Instead they just let someone generate yet more code and called it OK since they have a better designer than anyone else.
How do you think something like PostSharp fits into this sort of discussion?
This is something where I can use PostSharp to do things, certainly.
Usually I am frustrated of IL weaving because it is not rich enough, but this is certainly something that I would do there or using runtime proxies.
Interesting, we're evaluating PostSharp to help us generate the sort of code you show to allow us to perform dirty tracking of some of our domain entities.
When you say IL weaving (not a topic I'm massively knowledgable on) is not rich enough, what sorts of things do you mean it lacks?
See here for the main differences:
http://www.ayende.com/Blog/archive/2007/11/27/The-difference-between-meta-programming-and-IL-weaving.aspx
PostSharp is very interesting, because it takes care of all the reflection emit stuff for you.
The problem is that I am interested in more than just OnEntry/OnSuccess/OnFailure in the general case.
You can 100% do what they did here using PostSharp, just to be clear.
Linq to SQL is not threadsafe, so why do we need threadsafe events in otherwise non-threadsafe class.
You (we) are not supposed to read generated code, it is for compiler
If you decompile bytecode after IL weaving, you will see exactly the same code as in your example, so what's wrong to generate it in the first place
4!. IL weaving (as a method) is not supported by Microsoft product support - duh...
Alex,
1/ Since the best practice implementation is a single line of code longer, I don't see why not follow that approach rather than the non thread safe one. Even if you don't fully support it, doing it in a way that would randomly fail is bad.
2/ Sorry, I read generated code, because code is code. See the rest of the comments there for the details why.
3/ Not really, what I'll see is aspect hooks, nothing else.
4/ Their issue, not mine. They can choose not to support it, but it is incredibly powerful technique.
3/ Don't partial methods OnPropertyChanging/OnPropertyChanged look like aspect hooks to you?
Alex,
No, they are not.
There are badly thought of hack to get around the resistance in MS to do actual AOP.
Have you heard of any softening in MS's view on AOP?
I hope the ALT.NET community can convince MS to add support for the things we believe we need to improve development, who knows if that will happen though.
For PostSharp examples of INotifyPropertyChanged and IEditableObject, see http://doc.postsharp.org/UserGuide/Samples/PostSharp.Samples.Binding.html
Yet another reason Microsoft needs to bake AOP into the framework. Why should they be the only ones that get to do it with things like CAS and PrincipalPermissionAttribute?
I have thought about using postsharp or other ilweaver instead of codegen. But I have strongly decided against it. IL weaving is just too cryptic.
I can look at generated code, I can step through generated code, I can show this code to the new team members just like "we do no dark magic, you can see exactly what we are doing".
IL weaving and runtime IL generation I will leave to the well-tested and documented frameworks like NHibernate. Otherwise it may be a maintenance nightmare -- things that kinda magically work but nobody knows how or why.
Andrey, I had a similar reaction to IL weaving before I tried PostSharp. But once I skeptically gave it a try, I discovered it allows me to step through the code quite intuitively, with the debugger transitioning from aspect code to app code and back again just as I would expect.
As far as being well-tested and well-documented, PostSharp does quite well by both measures. Give it a try! ;-)
That's like saying: here is this new and shining framework, make use of it, but you can't read the code.
Even if code is auto generated, I have to udnerstand how it works, and for this I will read it
@Andrey
I get what you are saying but to be honest when evaluating it I found the ideas behind PostSharp to be quite simple and had no problem debugging through it.
I should say that the code that I'd use PostSharp for is the sort of thing shown in this blog entry, not necessarily the sort of code I want to see when browsing through my domain classes (personally!).
It is a tradeoff but to me PostSharp is a very interesting piece of software.
I have been reading with interests about the fact the the above code is bad especially the linq Generated stuff.Well Can you actually show an equivalent good code?It would be interesting to see.
Also I disagree with codeGeneration bit.Code Generation based on templates can save thousand of hours.
Anyway
can wait for the equivalent good code !!!!!!
I'd appreciate seeing the corrected code too please.
Take a look here:
http://www.ayende.com/Blog/archive/2007/04/17/Advance-Extending-NHibernate-Proxies.aspx
Comment preview