Let's say you wanted to generate and render this XML fragment:
<status code="1" /> <data> <usergroup id="usr" /> </data>
Here's a fully object-oriented way of building it:
System.Text.StringBuilder sb = new System.Text.StringBuilder();
XmlWriterSettings xs = new XmlWriterSettings();
xs.ConformanceLevel = ConformanceLevel.Fragment;
xs.Indent = true;
XmlWriter xw = XmlWriter.Create(sb, xs);
xw.WriteStartElement("status");
xw.WriteAttributeString("code", "1");
xw.WriteEndElement();
xw.WriteStartElement("data");
xw.WriteStartElement("usergroup");
xw.WriteAttributeString("id", "usr");
xw.WriteEndElement();
xw.WriteEndElement();
xw.Flush();
return sb.ToString();
That seems like a tremendous amount of code to do something relatively simple. I could abandon the pure object approach and do it in two lines of code:
string s =
@"<status code=""{0}"" />
<data>
<usergroup id=""{1}"" />
</data>";
return String.Format(s, "1", "usr");
It's far less code. And it's much easier to read!
I've worked with developers who insisted that everything had to be generated through an object model, even if the object-oriented way required many times the amount of code. Although I haven't worked with Daniel Cazzulino, he typifies this attitude:
If you're using Response.Write, you're a dreadful citizen of the ASP.NET world.As my friend Victor said, "Response.Write is there just for compatibility reasons and for old script programmers to not feel lonely".
An app written in such a way will not only be difficult to maintain and evolve, it will be almost impossible to customize (specially its layout), will never catch up with the upcoming mobile features and just hurts the eye. Everytime I see a Response.Write, and specially if it's not even kind enough to use HtmlTextWriterTag, HtmlTextWriterAttribute and HtmlTextWriterStyle, the developer who wrote it is instantly removed from my in-memory list of good ASP.NET programmers.
Like Rick Strahl, I'm not convinced the verbosity of objects like HtmlTextWriter and XmlTextWriter are warranted.
The idea of "write once, run anywhere" via a complex set of objects and adapters is a pleasant one, but it also adds a heavy burden of verbosity and complexity to your project. And you probably aren't gonna need it anyway. Sometimes it's simpler and clearer to render the HTML or XML directly to the page without all that OO cruft gunking up the works.
But, but, but, what happens when your params have a literal quote in them someday?
Adam Vandenberg on June 22, 2006 4:20 AMThose two code fragments don't show object oriented vs structured programming, they show using one function (which implements a simple parser) verses using many functions to do the same thing.
(Well a similar thing, I'm guessing the second piece of code will not handle any changes to 'id' or 'code' as well as the first)
Not that I disagree that an OO only policy is a bad idea, it's just that the example doesn't show it.
So, what happens to values that need escaping in the string example?
*BOOM*
What you get from a library is domain knowledge that you as a library user may not need to care, or even know about.
But I agree that the first example is very verbose compared to what it does. So, the interface sucks. Are there no XML libraries with simple interfaces for solving simple problems?
/J
So, what happens to values that need escaping in the string example?
So use an existing function that sanitizes and escapes user input for output in XML. No big deal.
Are there no XML libraries with simple interfaces for solving simple problems?
Here's the scary part-- that *IS* the simple XML library! I could easily construct a much more verbose example using other Xml* objects.
Jeff Atwood on June 22, 2006 4:28 AMThere is nothing wrong with object-orientation.
The basic problem you have is imperative versus functional-programming (composition) styles for constructing data.
If you used LINQ, you would have both OOP and functional styles combined.
Wesner Moise on June 22, 2006 4:34 AMSeems like this could be partially solved using code gen to create the writer code from an xml snippet.
Also, depending on the situation, serialization is another OO way to get the XML you want without using the writer or string-building approach.
Daniel on June 22, 2006 5:15 AMJeff,
I'm all for the simplest thing that could work, but the example above is not going to cut it.
As the other people mentioned, your solution would generate invalid XML in a range of scenarios.
Yes, you can handle that, but pretty soon you'll find yourself writing more code than the original way.
Worse, you will fix each issue as a bug fix that would never come up if you used the XML API from the start.
your solution would generate invalid XML in a range of scenarios
How so? This is scaremongering! If we modify it this way..
String.Format(s, XmlEncode("1"), XmlEncode("usr"));
(Which, by the way, is only necessary if these fields are derived from user input.)
I don't see a "range of scenarios" where the XML will be invalid..
Jeff Atwood on June 22, 2006 5:24 AMI think what's missing in the conversation is the generating XML or HTML via string building is error prone. There's a tremendous amount of ill-formed XHTML out there that is caused by string builders. But I agree, XML Write is too complex.
Randy Charles Morin on June 22, 2006 5:52 AMgenerating XML or HTML via string building is error prone
Let me play Devil's Advocate for a minute.*
And generating XML or HTML via umpteen billion Xml*.* methods _isn't_ error prone?
I had to experiment quite a bit with the Write commands to get the output XML to match the requirements. Was that error prone? You bet it was. Particularly compared to just cutting and pasting into a string.
* I know, also known as the entirety of my life. Har har.
Jeff Atwood on June 22, 2006 6:02 AMThis has successfully argued that if you want to write a 4-line XML fragment, using the XmlWriter is overkill.
In most trivial examples, we find that using powerful libraries takes more work than not using them.
However, what would this turn into when the example becomes non-trivial? How easy would maintainance be if an element has 10 attributes and you want to remove the 5th one?
Personally, I've got enough things to worry about to be distracted by getting the XML syntax right.
Andrew Shepherd on June 22, 2006 6:09 AM How so? This is scaremongering! If we modify it this way..
String.Format(s, XmlEncode("1"), XmlEncode("usr"));
What are you talking about? Scaremongering! LOL.
The "improved" code you wrote is a mess, and prone to mistakes (you have to remember to escape every time otherwise you risk introducing bugs).
There is *nothing* wrong with a fully OO aproach to programming. As Johan L pointed out, its just the interface that sucks.
Once you realise its just a poor interface, pull your finger out and write your own wrapper Class for XmlWriter that allows you to program in a succinct and elegant fashion.
Then you get THE BEST OF BOTH WORLDS!!
For an example of a wrapper class that achieves this level of elegance in writing DOM based code in an efficient OO manner see DOM JS http://dom.simplesideias.com.br/
A wrapper for XmlWriter?... you might have to roll your own...
Mini Gav on June 22, 2006 6:13 AMIn ruby, the code looks much better:
a href="http://www.rafb.net/paste/results/x9VHuZ53.html"http://www.rafb.net/paste/results/x9VHuZ53.html/a
(from Builder documentation)
After living some time with ruby, each time I go back to C# or Java I just hate the overhead of having to declare everything by type even if I don't really need the type safety.
I've been on any number of HTML projects with all kinds of different programmers over the years.
I'm yet to see a programmer who always remembers to escape their output correctly with string concatentation. This includes me, and I'm very aware of the issue. Encoding issues like that are probably the number two cause of security vulnerabilities; with that approach, you forget *once* to escape correctly, and you've got a potential XSS security vulnerability on your hands.
On the other hand, I've found that a full OO-esque approach has had comprehension difficulties that make it tough to just throw a web page at somebody and expect them to work on it. Personally, I *love* the OO approach because it allows you to create functions for recurring snippets (and I wouldn't be caught dead using a language or library that was a quarter than verbose; I've written libraries in languages where the penalty is about two chars an "element" (tag, attribute, etc.), which came back almost instantaneously due to the functions I got to write), but this is also something I've experienced people having fun with.
Where I work now, the lead developer and I went back and forth on this issue, and we settled on a compromise I've found acceptable, and has been working for us (that is, people aren't accidentally writing XSS vulnerabilities left and right): We changed the default escaping mechanism to be XML/HTMLEscape, instead of straight concatenation. We're in an ASP-esque enviroment that uses [%= %] as the shortcut for rendering, and then we added [%! %] for "no escaping" inclusion. Square brackets are used because there is no indication of whether this comment box will take HTML, and there is no preview. (And we'd use the ASP templating to do that substitution, not string manipulations in the program.)
This has avoided the very real objections raised about crossing encoding planes (very dangerous, should not be underestimated!) while still retaining the practical essense of the second solution.
Jeremy Bowers on June 22, 2006 6:23 AMJeff,
Your code sample:
string s =
2 @"status code=""{0}""
3 data
4 usergroup id=""{1}"" /
5 /data";
6 return String.Format(s, "1", "usr");
Always produce invalid XML because the status tag has no end bracket and also has no closing tag.
This was propably just a typo, but it just confirms that not using an XML API is error prone.
The benefit of using XML APIs is that is always generate well formed XML. Using string to build XML can introduce bugs that are only discovered at runtime.
I just checked your code again and it looks fine.
I guess there was something with my browser because I could swear the closing tag and end bracket were missing before I post my incorrect comment.
there is no indication of whether this comment box will take HTML
I guess the "Your comments: (no HTML)" text is hard to see. I'll modify the template..
This was propably just a typo, but it just confirms that not using an XML API is error prone.
Sure. You're right, I corrected it. But I think having literally 8x the amount of code is also error prone. More code = more errors.
Did you guys see the Ruby example linked above?
---
builder = Builder::XmlMarkup.new(:target=STDOUT, :indent=2)
builder.person { |b| b.name("Jim"); b.phone("555-1234") }
will generate:
person
nameJim/name
phone555-1234/phone
/person
--
Jeff Atwood on June 22, 2006 6:45 AMA simple PHP function lets you do it this way:
$x = XML('status', array('code'=1),
array('data', NULL,
array('usergroup', array('id'="usr"))));
A Perl equivalent would be even shorter:
$x = XML('status', [code = 1],
['data', [],
['usergroup', [id = "usr"]]]);
(Note I'm using [] instead of {} because I want the attributes to be ordered.)
No doubt any language with the equivalent of C's varargs could manage this sort of thing.
(Oh... and if this post is unreadable, blame whoever it was who decided this blog doesn't need a comment preview button. Dumb, dumb idea.)
Eric TF Bat on June 22, 2006 7:20 AMI suspect you were being partially sarcastic, but that *does* help.
No two comment boxes seem to work alike.
Jeremy Bowers on June 22, 2006 7:25 AMI agree with Jeff to a degree, and others that it's mainly the interface of .NET's current Xml objects that cause the suckage.
Just for shits and giggles, go read this article on Lisp:
http://www.defmacro.org/ramblings/lisp.html
...And then check out Sahil's series of articles on what's coming for C# 3.0:
http://linqinaction.net/blogs/sahilmalik/archive/2006/06/18/24.aspx
All I can say, is that it looks like Microsoft is on the ball with this issue.
Jeff Perrin on June 22, 2006 9:18 AMIf you want to write out a small amount of XML quickly then your approach of just doing it works OK and is, as you say faster to code. It allows you to generated structured content in an unstructured way.
I guess using the DOM approach would be a midway house in coding verbosity. Always thought the XMLReader and XMLWriter were designed out and out for execution speed and low memory usage rather than developer productivity.
I guess LINQ will help here ?
Chris Brooksbank on June 23, 2006 2:23 AMAs noted in other comments there is a best of both worlds... which is really helpful when creating larger documents that have a lot of boilerplate...
doc new XmlDocument(new XmlTextReader(boilerplateInString))
and then XPathNavigator over this to navigate to nodes and set the real values.
Use the object model where it gives value (handle the right encoding, serialising the document, getting the syntax right), and the easy way when applicable.
XPathNavigator.AppendNode(XmlReader) and similar methods also allow insertion of many nodes.
Richard on June 23, 2006 2:53 AMThe fun stuff comes when you have an entire complicated system building xml, xhtml or x(something else?) documents. Have you guys looked at the differences from .Net(c# or vb.net), php to ruby? I know that it would be a sin for some people here :), but imagine you should port your vb.net oo xml generation stuff to ruby? That would be quite a lot of rewrite if you ask me.
You don’t always need valid xml, sometimes it is just enough with well formed xml documents. Of cause we should always try to do better, but I don’t think you need to use all your gun powder on every line of code you write. If the xml you generate needs to be very strict formatted then yes you should of cause provide valid xml, but if it just is some little test application that needs a simple xml save function, then do it fast. Suit the code for your needs. There is NO correct way to generate xml. And that is how it should be.
E4X is a nifty Javascript enhancement that makes XML a first class type.
So in E4X the code would look a lot like the string example, but instead of being a string, it would be an XML data-structure.
The XML elements become exposed as properties on the object holding the object graph:
var x = status code="" /
data
usergroup id="" /
/data
x.status.@code = 1
x.data.usergroup.@id = "abc"
Is it just me or does the 'OO' version appear to be just procedural code using an object-based API? The repetitive work doesn't seem to be abstracted at all.
Surely an effective OO API would allow me to take what we know about XML (such as that tags that pertain to content have closing tags).
So where does that leave us? The 'OO' way is an example of a poor interface (and not many seem to disagree here). The 'short' option might be served by a template approach if you are just formatting a message to another system. Nothing would stop you doing this in a succinct OO manner either.
We develop in PHP primarily - if we had 1 message to create it would be just a hand-typed string. When the requirements change it would likely have further OO abstractions applied (we don't like operating in global scope so we'd have started in the scope of some object or another...)
wioota on June 23, 2006 5:23 AMSince it seems like it will help most of the commenters:
Forest -
- Trees
In the .NET world, couldn't you create a class called "data" (or whatever) which has a property that is a class called "usergroup" with property id.
Then you could create an inheritable class that itself inherits the XML Serializable Class and create a function in the base class that outputs your class as XML, using the appropriate "ignore" and "attribute" functionality available to the XMLSerializable class.
Then, your inherited class already has the mechanisms to output that object directly as XML, plus it's well-tested code (I assume) by Microsoft and the community.
This seems to me to solve the problem of a) type-safe security and b) error-prone XML and c) Happy-go-lucky OO.
But, I agree the XML Classes are cumbersome at best. In the words of Larry the Cable Guy sometimes you just have to "git 'er done".
I hesitate in posting to this group as I don't consider myself to be a "programmer's programmer", so if there are flaws in my plan please feel free to let me know :)
Doug on June 23, 2006 5:45 AMThis may be a bit of a stupid point but the example is exactly the kind of situation where you are putting the data in an xml document just because XML is what people use. There are loads of entirely valid uses for XML but anything that is simple enough for a trivial example is very likely to actually be so trivial that you might be better off just using plain text file with some simple formatting.
The outcome of that is that everyone ends up criticising the example and ignoring the point you were trying to make. Just like I have just done.
For me, the problem with the XML libraries pretty much reflects the problem with XML itself- I'm all in favour of interoperability but I don't think I necessarily need that much verbosity for everything I do...
Ben Moxon on June 23, 2006 6:25 AMIn my personally experience as soon as developers start using string variables to hold XML we start getting invalid XML problems. And when one system is passing XML around to other systems this is a real pain. Unless the XML is ridiculously trivial I would stick to using objects if you can.
Paul on June 23, 2006 6:59 AMIts called a Templating Language and its not just good for XML, but for (X)HTML, email, reports, whatever. String.Format() is just a very very simple templating engine. From an OO/Architechture standpoint I think this is actually better because it means the view isn't mixed in with the rest of your code. And like Jeff said, its faster, easier to understand, less code and more maintainable.
Gareth Farrington on June 23, 2006 7:25 AMI don't think it's the OO either that's the problem. xw is supposed to be Xmlwriter. So,
why are we having to tell it to writeThis, writeThat, and writeTheOther? All those methods should lose the first 5 chars from their names. If it is to do something *else* with them, then be explicit.
If we can't have blocks, as per the Ruby example, then why doesn't startElement take the attributeString and the nested element as parameters? It's not just the RSI of typing that
would be saved, it's the cognitive load of the poor person who has to maintain it later.
Using the code example in this article as an argument on when and where or even the validity of using OOP principles and code is like using a flower to compare and examine the properties of a human. They both are organic creatures, to be sure, but there the simularity ends. Thier concept and deterministic purpose is simply at odds with each other. So too are the comparison of coding methodologies behind script oriented code and object oriented code. They not only come from different worlds and have differnt histories, thier intent for solving problems are completely different. Scripting languages like classic asp, sql, pearl and others are simply relative language scripts that at some point have to be interpreted and transformed back into objects in c++ or some other object oriented languages anyway. Object oriented languages were born to help programmers who were originally programming thier code in assembly to have more tools and prevent them from performing repetitive and non-automated tasks. Scripting languages as well, were designed to perform a specific task, to allow simplistic access to functions and creation of an underlying oo framework in a simplistic manner. I have been presented with the argument that making a simple primitive script in code is more efficient than using objects, thus:
for(i = 0;isomeValue;i++)
object obj = collection[i]
is more efficient than
foreach(object obj in collection)
because the first uses a simple iteration script and the second uses an iterator object to index through the collection. This is true for a very simple application, because the first way you are minimizing the number of objects in memory i.e no iterator object. But what if you have a more complex model? What if instead of a simple collection iteration you had a hundren thousand word essay to parse? Using a simple primitive collection of objects would be very inefficient then. So mabey choosing a Flyweight pattern to share instances of characters instead of creating them over and over in memory seems to be the more effective and optimized way to do things.
To understand something you don't first refute it before you understand it, you understand it then form your opinions on your new understanding. It seems like many junior programmers like the author has not had the experience to understand why you use oop and when not to. More complicated problems simply take a better solution. I do understand that some programemrs who have found themseleves on the positive side of understanding something about code can be quite enigmatic and arrogant about thier knowledge, or maybe do not communicate thier knowledge in an effective manner, which puts off people who do not have this knowledge. Or maybe you are making a good point when you say that oop does not cover every situation, which I would agree with because no single soution is a global boilerplate in computer sciences. But what the author needs to understand is there is a reason that evolves around understanding and thought towards a problem, and part of the understanding revoleves around understanding all the tools availiable without prejudice. Too often I have heard junior developers say that they don't understand why you use oop principles, when this other way is simpler. That argumentative attitude puts you at odds with knowledge. It would be better to ask questions and compare notes with other developers, and educate yourself into a place where you can make a competant argument towards a solution based on knowledge, instead of bullishly refusing to investigate your facts first. Just a thought, but in my mind arrogance in programmers is like having your trash man tell you your garbage stinks. No matter how smart any of us are, there are thousands smarter. So why waste time? Thanks for reading.
Ruby is like orange zest in chocolatte, it just makes everything better.
I think the .NET XML classes were designed by the same kind of people who worked on XSD. To paraphrase Capote, they aren't programmers, they are typists.
Scott on June 23, 2006 9:18 AMcfprocessingdirective suppresswhitespace="yes"
?xml version="1.0" encoding="utf-8" ?
cfxml variable="xmlDoc"
root
status id="1"/
data
usergroup id="1"/
/data
/root
/cfxml
/cfprocessingdirective
cfdump var="#xmlDoc#"
Jeff, I was simply going to say "Amen!", but then I saw the hailstorm you set off.
Hmm... mostly minor details and missing the point.
Eh, I'll just do it anyway. Amen, Jeff, and thanks for piping up!
Rob on June 23, 2006 10:29 AMIdeally you would want your C++/.NET/Java/etc parser to be able to internalize an XML Schema, and then allow you to simply write any expression that would be valid under the schema. You would get compile errors if you are writing XML that doesn't match the schema.
It's type-safety without the bullshit of strong-typing.
Armen on June 23, 2006 10:52 AMIt's true, Ruby's Builder::XmlMarkup absolutely destroys anything else in terms of object-oriented XML construction.
Your XML fragment, as produced by Builder::XmlMarkup:
xml = Builder::XmlMarkup.new(:indent = 2)
xml.status(:code = 1)
xml.data do
xml.usergroup(:id = 'usr')
end
output = xml.target!
All of the data is escaped, all of the tags are closed, and the code looks almost exactly like the output. Shazam.
Coda Hale on June 23, 2006 11:00 AMRob, the first thing that comes to mind when I think "when object-oriented rendering is too much code" is not "you should go ahead and hack it together using strings." I usually think "then it's time for a new XML library."
More generally, if using an object model requires writing reams of soul-crushingly verbose code then it's not time to reconsider whether or not you should continue to employ an object model; rather, it's time to reconsider whether or not you should continue to employ the person who wrote the object model.
Given a constrained choice between "XmlWriter And The Dance Of Ten Thousand Functions" and "Just Don't Ever Use Ampersands", the latter is of course easier. But the choice is rarely so constrained, hence the number of people chipping in with their favorite language's substantially less verbose way of pooping out XML.
I wrote an XmlClassWriter and XmlClassReader once. It wrote and read a class to and from XML. It's very useful, as alot of the time I am just saving classes or arrays of classes to XML to save the state of something.
It wouldn't be able to easily write the fragment you showed, but to writing a class like:
Card
Suit datatype="Suit"Clubs/Suit
Pip datatype="Int32"3/Pip
/Card
You would do something like:
public class Card : XmlBaseClass
{
public Suit Suit = Suit.Clubs;
public int Pip = 3;
public Listobject GetXmlProperties
{
Listobject xmlProperties = new Listobject();
xmlProperties.Add(Suit);
xmlProperties.Add(Pip);
}
}
And then you would use new XmlClassWriter().Write(new Card());
I really should finish it, polish it and publish it. It's very useful rather than re-inventing the wheel alot of the time.
[ICR] on June 24, 2006 2:44 AMCard
Suit datatype="Suit"Clubs/Suit
Pip datatype="Int32"3/Pip
/Card
Rather.
[ICR] on June 24, 2006 2:45 AMJeff, the issue here is more with "Java's OO" than with "OO" in general.
Ruby for example has (as others already pointed out) the very nice Buider module that allows you to build XML through the use of nested blocks:
In this case, your example would be rendered as
xml = Builder::XmlMarkup.new(:target=STDOUT, :indent=2)
xml.status(:code = 1)
xml.data do
nbsp; xml.usergroup(:id = "usr")
end
the result?
status code="1"/
data
usergroup id="usr"/
/data
ouch. Was meant to say:
The result?
status code="1"/gt;
data
nbsp;nbsp;usergroup id="usr"/
/data
It's a tradeoff.
If you compose XML documents out of strings,
you're eventually going to make an invalid XML
document. Either because you do something silly,
like forget to close an element, or because you'll
get bad input and not validate it correctly. (Look at how endemic XSS is, and I haven't seen a practical web toolkit that eliminates it.)
I suppose you could invent a language that statically checks XML chunks in code and has $-substition for text with correct escaping.
"Too much code" isn't the problem with "proper" XML interfaces (OO or not.) The problem is maintainability -- you can look at an XML chunk and immediately visual the XML it generates. Even Masklinn's Ruby example involves a conceptual jump between representations. With Java or .net, people can compose the DOM objects in many different permutations, even spread the work across tens of methods, scattered across as many objects. (i) you have to (re)learn the XML API if you don't use it every day, and (ii) understand the right place to change it if you need to make a little change.
I'm a pretty good maintainance programmer, and I'll probably make the change right... After a while. I've worked with a lot of guys who would (a) just give up and go home, or (b) make a bad change and manage to screw up the version control system so it takes a few hours to back the bad change out.
Paul Houle on June 24, 2006 5:57 AMin Common Lisp + cl-who, it's easy. Just do:
(with-output-to-string (s)
(with-html-output (s)
(:status :code (- 3 2)) ; you can use code here, too.
(:data
(:usergroup :id "usr"))))
i love it.
anonymous lisper on June 25, 2006 4:42 AMMaybe a new VS refactoring option here would be nice. Highlight the string and convert to XMLWriter calls. Or highlight the XMLWriter calls and see it displayed as XML.
Chris Brooksbank on June 25, 2006 5:44 AMAgree with wioota and others above. Jeff, the "fully O-O" code you posted is to my mind anything but.
Here's what a (statically typed) O-O API to XML looks like: http://www.xom.nu/
Specifically: the level of O-O abstraction matches that of the XML document model. To use it, you would construct objects for elements and data matching that of the desired output and then (as a final operation) serialize it.
This level of abstraction sounds even more important when you are dealing with XML fragments like the one posted above. In this case you simply wouldn't serialize it, just return the objects to the caller.
Deferring the serialization till the last minute gives practical benefits: Most importantly it decouples the decision of which character encoding to use from the code that will generate each individual XML fragment. Instead of requiring every part of your application to standardize on a given character encoding, you can now support all of them.
In addition it lets you do pretty-printing which is always nice, if not essential.
Alastair on June 25, 2006 8:17 AMI think the main point for this post is "there is no universal hammer, you need to use the right tool for the job", which isn't really what the example (and the title) says. The problem isn't with object-orientation. The real battle we have to keep an eye on is between procedural and declarative code.
The object-oriented code on the original post is very much procedural, imperative. This isn't what we want. For this particular problem a declarative approach is much more appropiate. It simply is the right tool for the job, although the purely template-based solution is not (like many already pointed out).
The Ruby + Builder solution that some already brought to the table illustrates this point: it uses an object-oriented approach, but one that is much more declarative than procedural.
This post inspired me to write one of my own on my blog (in Portuguese): http://thiagoarrais.blogspot.com/2006/06/os-objetos-esto-te-matando.html
Thiago Arrais on June 25, 2006 9:06 AMSomeone replied that most commenters were missing the forest for the trees. So I'll start with the trees first:
* The example code using XmlWriter is typical procedural code. The fact that there are objects involved doesn't mean that the code is OO. Of course, you could argue that the problem is really in the overhead of too-structured code in cases where there are more simple, albeit less "pure", solutions.
* Better OO xml libraries (and arguably better languages) lead to more readable code. And, as the Ruby example mentioned above, sometimes to more terse code, as well.
In more general terms, I don't think that object orientation per se implies in much overhead all of the time... For example, look at this post by James Robertson using smalltalk to extract info abot his feeds ( http://www.cincomsmalltalk.com/blog/blogView?showComments=trueentry=3318232350 ).
Or take a look at Martin Fowler's post showing a small OO faade he created for driving a graph plotting utility: http://martinfowler.com/bliki/ .
Both are simple one-off tasks nicely written in OO fashion.
My point is that structural overhead is always bad (and as an "enterprisey" Java developer I saw my fair share of overengineering...), but we cannot blame object orientation in general for bad design.
Someone replied that most commenters were missing the forest for the trees. So I'll start with the trees first:
* The example code using XmlWriter is typical procedural code. The fact that there are objects involved doesn't mean that the code is OO. Of course, you could argue that the problem is really in the overhead of too-structured code in cases where there are more simple, albeit less "pure", solutions.
* Better OO xml libraries (and arguably better languages) lead to more readable code. And, as the Ruby example mentioned above, sometimes to more terse code, as well.
In more general terms, I don't think that object orientation per se implies in much overhead all of the time... For example, look at this post by James Robertson using smalltalk to extract info abot his feeds ( http://www.cincomsmalltalk.com/blog/blogView?showComments=trueentry=3318232350 ).
Or take a look at Martin Fowler's post showing a small OO faade he created for driving a graph plotting utility: http://martinfowler.com/bliki/ .
Both are simple one-off tasks nicely written in OO fashion.
My point is that structural overhead is always bad (and as an "enterprisey" Java developer I saw my fair share of overengineering...), but we cannot blame object orientation in general for bad design.
Firstly did anyone else notice that this is not well formed XML? I can only assume that this is part of a larger xml document since there is no root element.
In any case, the easiest way to do this OO would be to simply serialize it as stated above. You wouldnt even have to write the code, since the .net framework comes with a handy little tool called XSD.
So the OO code effort pretty much becomes defining the schema and typing:
xsd myschema.xsd /c
and the code to consume the serializable object is something like:
Dim serializer As New XmlSerializer(GetType(myClass))
Dim _myClass As New myClass()
With _myClass
.status = 1
.usergroup = "usr"
End With
Dim writer As New FileStream(filename, FileMode.Create)
serializer.Serialize(writer, _myClass)
writer.Close()
It never ceases to amaze me how people knock what they dont understand.
SB
Scott Benjamin on June 26, 2006 7:00 AMWrite an XSD for it. You can do this by building a DataTable for it. That calling the Write Schema Method. Afterwhich the code looks like this:
DataTable MyDataTable = new DataTable();
MyDataTable.ReadSchema(@"c:\my.xsd");
//Pull Data in from user input here
//Use DataAdapter or pull values off the Form
MyDataTable.WriteXML("output.xml");
Using a StringBuilder is overegineering the issue.
Josh on June 26, 2006 7:40 AMA little late to step up to the table maybe but here are my thoughts:
http://www.thejoyofcode.com/XmlWriter_or_string_concatenation.aspx
Josh on June 27, 2006 2:16 AMI didn't quite get this:
"I've worked with developers who insisted that everything had to be generated through an object model"
How is the string class that you use NOT an object model?
Also in both examples you are solving this problem in a function (judging from the return statement) so how is this solution a
"fully object-oriented way of building it"
Functions are used in procedural programming and if you really tried a more object-oriented way of solving this maybe you would't write this article in the first place...
Christos Constantinou on June 28, 2006 5:48 AMI can see your point Jeff, I agree with you 100%; the verbosity is killing the fun. My usual solution to this situation is to create my self some helper methods.
Using the HtmlTextWriter as an example (because I have that on hand now):
private void RenderTag(HtmlTextWriter writer, HtmlTextWriterTag tag, string text)
{
writer.RenderBeginTag(tag);
writer.Write(text);
writer.RenderEndTag();
}
The above method makes it easier to render a simple open-close tag. Then you can create other, more specialised methods.
public void RenderCell(HtmlTextWriter writer, string text)
{
RenderTag(writer, HtmlTextWriterTag.Td, text);
}
Although I think the fact that I have to create such methods outlines a pretty serious flaw in the design of these objects.
James Gregory on June 30, 2006 7:01 AMWhen I read this post a month ago I agreed with Jeff, that it does seem to be overkill to write so much code for a few lines of html or xml. Last week a project ended up on my desk that required generating html forms (not asp.net but vanilla html with input boxes and tables) so I happily set off with my System.IO.TextWriter and started spitting out my html strings "div style=\"foo:bar;baz:box\"" etc.
It all worked quite nicely at first, but as I started adding more complexity to the html the code got more and more unreadable. That's when the light came on.
All those HtmlTextWriter.RenderBeginTag and AddAttribute methods are designed to work with the asp.net rendering model :
OnPreRender
AddAttributesToRender
Render
RenderChildren
RenderBeginTag etc.
So that when you start subclassing those controls, you can add content in the correct place and be sure that the "new" attribute that you just added isn't going to get duplicated in the output, or that the css styles get written to the right attribute.
I just spent a day rewriting all of my html writing code along the lines of asp.net and I now have a far cleaner and more robust model to build on.
So for what it's worth, I don't agree with your post anymore Jeff. Even though my example is html you can easily apply the same principles to xml creation.
Quote: "If you're using Response.Write, you're a dreadful citizen of the ASP.NET world."
Oh dear, here'a a nice link for anyone who seconds that notion. It's entitled: "Improving String Handling Performance in ASP Applications" and was written by James Musson Developer Services, Microsoft UK
http://msdn.microsoft.com/library/en-us/dnasp/html/aspstrcatn.asp?frame=true#aspstrcatn_testing
iObject on July 18, 2006 11:49 AMSorry, but shorter code doesn't always mean better design. OO is about reusability and maintainability.
Pat on November 8, 2006 9:25 AMOh yeah, and that first example of generating some
simple xml is so obviously more reusable and maintainable.
Yeah, Its sort of like the ineffectiveness of trying to read a highly threaded forum discussion in a flattened purely linear presentation, it's quite unmanageable!
John on November 9, 2006 1:50 AMJust want to second what Scott Benjamin said above (and which I'm surprised nobody else said sooner).
The obvious thing to do in many scenarios is to simply write (or generated from XSD) a class which covers your XML schema. You set the properties, you serialize, you deserialize, etc. Simple stuff, clean code.
For alot of real world cases, this is better than either of the solutions being tossed about here.
jd on November 9, 2006 5:13 AMPrecisely my point is not to use string writing.
Either approach (Xml writing or using an object model, either a business object + XmlSerializer or composition of ASP.NET built-in server controls) is generally better.
For trivial cases like the ones you propose Jeff, it may sound OK. But real world is plagued by non-trivial cases, and I know from experience that once you let a lazy developer string-concat a piece of output, they will rarely exercise good judgment as to when it's just too much.
Other options are separating the rendering of the output from your program logic, by externalizing it in a proper parameterizable template like T4 (from the DSL tools) or CodeSmith or NVelocity, etc. That is actually my preference when you're not rendering UI.
Daniel Cazzulino on January 10, 2007 8:44 AMmy 2 cents... the object oriented code isn't sufficiently abstracted away. I would encapsulate all that crap into a much simpler constuct. Who wants to write all that code over and over?
Perl ftw, btw.
apeinago on March 5, 2007 12:53 PMThat's why I like E4x
AlexK on October 31, 2007 1:19 PMBoohh to the author of XmlWriter. You can be short in Java as well:
Element parent = ...
parent.add( element("status").attribute("code","1) )
.add( element("data")
.(element("usergroup").attribute("id","usr"))
);
parent.flush();
That wasn't so difficult. And it looks much more OO, since you add atttributes to an element rather than remembering to open and close.
Werner on November 12, 2007 7:49 AMI've written some (small) server controls in C# and have to agree that the overhead using the "Writer" classes is ridiculous. I tried it that way for a couple of days and then totally gave up on it. Not only was it a burden to use, but it was generating more bugs because it was VERY difficult to simply look at the code and know whether or not every StartElement() had a matching EndElement() - much more difficult than looking at actual XML. It's easy enough looking at the simple example in this post, but pepper that with about 50 elements at various nesting levels and your eyes will start to glaze over very quickly.
The DOM model has its uses, to be sure. One example is program options in the Win32 world; yes, .NET has a vast library of persistence classes, but Win32 doesn't, and when I wanted to store program options in XML it was pretty easy to wrap existing DOM interfaces such that arbitrary new options could be added with just two extra lines of code (one to load, one to save).
A lot of these classes were written to address specific needs, and people shouldn't assume that simply because it's *possible* to use them in a specific situation means that they *have* to be used in that situation. No best practices!
And XSS is overrated - how about instead of using these clunky writer classes or remembering to escape every single output string, you just escape the form INPUT, once? How many common scenarios are there where you can escape the output but not the input?
Aaron G on February 6, 2010 9:47 PMI think everyone is missing Jeff's point. He's talking about using the right tool/methodologies for the job. Not necessarily a correct, or incorrect way to deliver XML.
Sometimes it is much simpler to just write procedural code than it is to write a full-blown, multi-tiered, object-oriented enterprise application just to create a three element XML document.
Brian Chiasson on February 6, 2010 9:47 PMMy biggest problem with the example given is that visually, the object-oriented method is harder to follow. It's up to the individual reading the code to mentally keep track of when a tag is opened and closed to tell which are wrapped inside other tags, since Visual Studio will put everything on the same tab level by default.
In the example Jeff provided, it's simple, but if you're producing a long XML document, it becomes tough to read.
Jake Vinson on February 6, 2010 9:47 PMI won't argue about your statement that OO may be overkill, but I'll point a flaw in your argument. Here's a counter example of a pure OO implementation that is about the same size as the string format example (written in python)
import yaml
x = {}
x["status"] = { "code" : 1 }
x["data"] = { "usergroup" : { "id" : 1 } }
print yaml.dump(x)
The output is like this:
data:
usergroup: {id: 1}
status: {code: 1}
There are maps, strings integers, a function (a method from object yaml). Nothing else. Yes, I know that I cheated, that your client or boss wanted it on XML, but you can't deny it. It's proof that the OO implementation you chose sucks and there are implementations that are even cleaner than the example you wrote.
The comments to this entry are closed.
|
|
Traffic Stats |