Why is using built-in IDE features and wizards a bad thing?



  • So I've been thinking lately about something.  When I learned programming I learned VB.NET and then moved to C#.  I've never done C++, and know some Java only because of its similarity to C#.  In my experience, I've noticed that the majority of .NET guys seem to either A) Use Microsoft's built-in wizards the like for things such as databinding (Typed Dataset + ObjectDataSource, for example), or B) Shun anything premade and write their own mappers/ORM layer, even with very good third-party tools available.  Most .NET guys also don't seem to give a lick about patterns and proper architecture.  This is in contrast to what I've read about the Java community, which has a strong background in design patterns and embracing open-source, third-party library tools.  So for the longest time I started to wonder what the hell's wrong with .NET - does it just attract the "Morts" of the software world, the VB6ers who happily hack together code without thought? The fact that the majority of .NET books tend to be quick-and-dirty instead of showing the "right" way seems to lend itself to this.

    But lately I've been thinking - take the databinding example before.  The Java world doesn't have anything like a typed dataset that I'm aware of (and remember, I'm not that familiar with Java and its related technologies).  It certainly doesn't have wizards and IDE built-in helpers.  So maybe I've been thinking wrong, and its not dirty or "Mort" like to use typed datasets in an application that keeps the tiers separate.  I bought a book on development with Visual Studio Team System 2005 because it demonstrated a complete system from inception through completion, and in the development chapters the fictitious consulting team makes use of typed datasets for the data layer, instead of writing their own set of mappers and DbXXX classes like I've seen teams do so far in my career.  And this is, despite the book focusing on certain aspects, a good example of a "real world" enterprise system.

     So this got me wondering.  Why exactly is it considered a "bad" thing to use typed datasets and certain built-in wizards when developing applications?  Now, granted, it might not be useful for all situations.  But it can certainly speed up the development process in the most common scenarios, and yet every developer I ask turns up their nose and mentions how "real developers don't use Wizards; they're for the Morts".  I'm still relatively new in my career, and I'm trying to become an expert in .NET, so it's not like I want to use the wizards without care of what they're doing.  It just seems easier and more effective to use the tools on hand, instead of re-inventing the wheel and writing your own set of data mappers, data classes, DTOs/DAOs, Factories to instantiate the DAOs, etc. etc.  It just seems like a ton of more code that's fulfilling the same purpose and also trying to compete with the over-architecting Java EE guys. 

    Can someone please enlighten me?   I want to learn best practices, so I can write code the "proper" way instead of learning bad habits (because said bad habits will screw me if I join a team that follows the right practices), but the things I'm talking about seem to be snubbed more out of "If it's not complex, it's not right" rather than "This is the right way to do it".



  • @ObiWayneKenobi said:

    So for the longest time I started to wonder what the hell's wrong with .NET - does it just attract the "Morts" of the software world, the VB6ers who happily hack together code without thought?

    In the world of software development, there are three kinds of people: there are those people who learn to use everything they can get hold of, and pick a tool for each job - not necessarily the right tool, but there is some kind of decision-making process involved here. They actually think about it. This group is the smallest, and all of the really good people belong to it. Secondly, there are the people who learn one thing and apply it to every situation without considering how appropriate it may be - we've all seen them. They're common, and largely useless. No matter how much you try to tell them how to do something, they will carry right on doing what they have always done. All you can do is quietly move them to a place where they can do no harm.

    Thirdly, there are the sheep: they follow whichever wind blows most proximately, doing what they are told without much real thinking or attachment to any particular method. In the absence of firm guidance, they will seek out rumour and supposition and follow that, then repeat these rumours to others of their kind; marketdroids frequently mistake this for a community, but it's really just a mob. Given a strong blast of marketing, they will all rush to follow it. Every time there's a new fad, you'll find them running to it and preaching about how great it is. A while ago they were chasing C++, then they moved on to Java.

    Now Microsoft's marketing machine has got them all clustered around .NET. Any apparent trends in that area are most probably just their mindless babble. Ignore them - in a couple of years they'll all have moved on to the next thing, and be producing clueless nonsense about that instead. You cannot learn anything meaningful by watching what they do, so you cannot learn anything by watching the "majority" in a region where the sheep currently congregate.

    A sheep is not necessarily a useless worker, but they must be given firm and continual guidance or they will produce vast quantities of stupid nonsense. They are only as good as their instructions. They are extremely valuable in QA.

     

    The fact that the majority of .NET books tend to be quick-and-dirty instead of showing the "right" way seems to lend itself to this.

    There is nothing remotely like an effort being made to prevent the sheep from publishing books.

    Can someone please enlighten me?   I want to learn best practices, so I can write code the "proper" way instead of learning bad habits (because said bad habits will screw me if I join a team that follows the right practices), but the things I'm talking about seem to be snubbed more out of "If it's not complex, it's not right" rather than "This is the right way to do it".

    This question indicates the wrong kind of thinking. "Best practices" are just a fancy way to describe a bunch of rules used to direct sheep. They have to be carefully crafted for each project, by somebody capable of rational thought. There are no universal answers. It is genuinely impossible to create a set of rules that will give good results in all scenarios (this has been proven analytically, it's one of the corollaries of the Halting problem).

    You may learn something from people's attempts to answer that question, but it won't be anything really important.



  • After assufield's sermon, I'd like to try to give some real-world answers to your question.

    As a rule of thumb, avoid situations where a wizard generates code you don't understand, but you have to mess with that code to make it do what you want.

    A wizard that saves you from doing repetitive work but generates readable output - fine. I bet it makes less typos than you. (Think of the tools in Eclipse that generate getters and setters)

    A wizard that generates complex code but you just use that code, and never have to look at it - fine. Actually, you can think of the compiler as being such a wizard.

    I don't do much in .net, but taking a short look into what "typed datasets" are, I think there is nothing inherently wrong with them. At least they are better than normal (untyped) datasets.

    BTW, java coders often use tools like "middlegen" to generate databinding code. Doing that by hand is tedious and gives you next to nothing. 

     



  • @asuffield said:

    Secondly, there are the people who learn one thing and apply it to every situation without considering how appropriate it may be - we've all seen them. They're common, and largely useless. No matter how much you try to tell them how to do something, they will carry right on doing what they have always done. All you can do is quietly move them to a place where they can do no harm.

    Thirdly, there are the sheep: they follow whichever wind blows most proximately, doing what they are told without much real thinking or attachment to any particular method.

    Personally, I prefer the "learn one thing and apply it to every situation" (aka "golden hammer") people over the "sheep". Let both groups make ten application over a time span of, say, 5 years.

    From the "golden hammer" people,  you get ten apps made in the same way, using the same tools in the same style. Most likely  those tools were not the best choice in all cases, but if the golden hammer is not a very bad choice, chances are that all apps work. From a maintenance point of view, it's not too difficult to maintain all those apps.

    The sheep most likely will have used at least seven different technologies (languages, frameworks, approaches) to build those ten apps. Most likely, in at least half of those ten apps, the technology of choice was not used as the inventors meant it to be used; i.e. it was use like the previous technology should have been used. Think of a C# programmer writing Java-like code. From a maintenance point of view, this is a nightmare.
     



  • @ammoQ said:

    @asuffield said:

    Secondly, there are the people who learn one thing and apply it to every situation without considering how appropriate it may be - we've all seen them. They're common, and largely useless. No matter how much you try to tell them how to do something, they will carry right on doing what they have always done. All you can do is quietly move them to a place where they can do no harm.

    Thirdly, there are the sheep: they follow whichever wind blows most proximately, doing what they are told without much real thinking or attachment to any particular method.

    Personally, I prefer the "learn one thing and apply it to every situation" (aka "golden hammer") people over the "sheep". Let both groups make ten application over a time span of, say, 5 years.

    Hmm, that's actually a pretty good name. Although it often tends to be more of a "golden shoe". 


    From the "golden hammer" people,  you get ten apps made in the same way, using the same tools in the same style. Most likely  those tools were not the best choice in all cases, but if the golden hammer is not a very bad choice, chances are that all apps work. From a maintenance point of view, it's not too difficult to maintain all those apps.

    The sheep most likely will have used at least seven different technologies (languages, frameworks, approaches) to build those ten apps. Most likely, in at least half of those ten apps, the technology of choice was not used as the inventors meant it to be used; i.e. it was use like the previous technology should have been used. Think of a C# programmer writing Java-like code. From a maintenance point of view, this is a nightmare.

    That's true enough, if the sheep were allowed to run off without direction - the "golden hammer" people are largely useless (they tend to be responsible for the "identical block of code, pasted a thousand times" things we see), but an undirected sheep is actively dangerous (and provides much of the front-page material). They're ignorant, they have no ability to recognise this about themselves, and there is no limit to what they might do. A large mob of sheep is only as intelligent as the stupidest google query in the mob.

    However, under a team leader who knows what they're doing, a sheep will flourish: with proper direction and no role in the system design, they can produce reasonably good code. Unfortunately some idiot then promotes them, and all hell breaks loose. 



  • I'll just make this as short as simple as possible:

    Just like any programming language,generated code and wizards are tools to help you in your work, however it is truely only helpful if you know whats going on, and why it's going on.

    You should always try to understand,with at least a basic level, of whats going on when you do anything that's generated. The whole idea of generated code is that's it will suit all general purposes of what developers are looking for so its speeds up the dev process, however there's always the exception. And by understanding what the generated code is doing or even to understand what code is going to be generated your going to know if the generated code is actually going to help or hinder you in your efforts.

    You may find you need to modify generated code, or even write your own code from scratch so it does what you want, the way you want, without doing things that aren't neccessary or making a later section of code more difficult or even impossible.

    'Real programmers' do use generated code but understand when it is useful and not. Otherwise 'real programmers' would be purely programming in machine code.



  • It should be noted that the highly recommendable book "The pragmatic programmer" has a short chapter dedicated to the topic of "evil wizards". If you don't have that book, buy it.

    http://www.pragprog.com/the-pragmatic-programmer 



  • I still consider myself quite new on the programming job (only 3 years, ASP.NET/C#, SQL Server database, a little MS Analysis Services, still my first job), and I don't like generated code only because I didn't write it. I'm kind of obsessive and paranoid on this, I don't trust code I haven't written myself. The only "generated" code that I used is 2 snippets and a custom template that I wrote for VS2005. The only way that I can trust a wizard is try it and undestand what it generates and how he decides what to generate.

    But I really think that wizards can help improve "productivity"... if you know how and when to use them.

    Considering typed DataSet, I'd say "why not", but at my job, we don't use them because of the always changing data model (added or removed data, data used for another purpose, etc.) and because "it's not the way we do it" (<= beware of this answer, be sure to always get a valid explanation for that (bad performance ? uniformity of the code ? whatever...)).

    Like everyone said, there is no universal right way. Each project is at least slightly different from the last one. At my work, we have some conventions (mostly about the formatting of the code/data model/whatever) and some "best practices" aka "everybody should do it this way so everyone can understand (and because some MS dude told us it was better this way)", and we try to follow them (well, at least, I try, and don't really know about the others...). But in general, everyone write code how he knows and what his small intellectual capacities or his boss' shortsightedness permits him to code, and they try to pick up tricks from coworkers (either good or bad). And fighting against (or trying to improve) this... well... if you're willing to try, good luck...



  • @Kokuma said:

    I'm kind of obsessive and paranoid on this, I don't trust code I haven't written myself.

    Hmmm... beware of the "not invented here" syndrome. 



  • @ammoQ said:

    @Kokuma said:

    I'm kind of obsessive and paranoid on this, I don't trust code I haven't written myself.

    Hmmm... beware of the "not invented here" syndrome.

    Yes, all too true... I'll soften a little bit what I said : of course, in the application that I work on, I didn't write everything and still call functions I didn't write (with the faint hope that they'll work), but in the worst case, I can check the code. And I must believe that standard libraries (e.g. System.*) will work if I want to code anything (no, I didn't rewrite the System.Collections and System.Text namespaces).

    Considering third party libraries (here, we use DotNetCharting and SyncFusion among other things), well... There has been some testing to know which library was the "least worse" and I do believe it's easier to work around the flaws of the libraries than write your own WTF that will barely manage to mimic what it's supposed to do.

    But I'll stand by my point on wizard's generated code : if I ever use a wizard, I'll read this generated code and try to understand it before commiting it.



  • I think that it all depends on what type of programmer you are. I have seen that some people do tend to just use some things, and not know what they do, regardless of the consequences (performance, scalability, etc.).  I don't think you can fault .Net for doing this, because just because its a feature of the IDE, doesn't mean that everybody makes a mess using it. Some people know how to organize the code correctly and use the right tools to their advantage.

    Personally, I might use the wizards for generating things like data connections or bound controls. I also use the designers (along with some third party tools) for form design.

     However, I wouldn't say that most don't give a darn about patterns and architecture. Used properly and with good organization, good developers can harness the wizard generated code to suit their needs. I don't do it much, but I'm sure I could work it in to my design in a clean way if I put the effort in.



  • Code generation is a good indicator of a flawed design. If your language of choice isn't malleable enough to avoid said generation, then you language is less than adequate for the task at hand. If the code generation is to work with an API (such as the one at my last job) then your API is poorly designed. I know it sounds like hyperbole, but it's true. Boilerplate == bad. Period.

    That being said, the "design flaws" that the necesary code generation reveal are usually not major (except in certain circumstances, like the API at my last job). I don't mind Windows Forms code, but I wish that there was something simpler behind the scenes for laying out forms.



  • @djork said:

    Code generation is a good indicator of a flawed design. If your language of choice isn't malleable enough to avoid said generation, then you language is less than adequate for the task at hand. If the code generation is to work with an API (such as the one at my last job) then your API is poorly designed. I know it sounds like hyperbole, but it's true. Boilerplate == bad. Period.

    That being said, the "design flaws" that the necesary code generation reveal are usually not major (except in certain circumstances, like the API at my last job). I don't mind Windows Forms code, but I wish that there was something simpler behind the scenes for laying out forms.

    You couldn't be more wrong.  Please read "The Pragmatic Programmer" for more info on generated code.  

     

    PS.  I suppose you have never used a compiler?



  • I think this specific example is a case of a situation where Visual Studio is just plain a better tool because of all the money and expertise pumped into it.  There are many Eclipse plugins that try to do the same type of thing you're describing above for Java development and they don't seem to catch on outside of a niche market.  Some of these plugins are actually quite good but they cost money, and honestly no one is going to pay money for an Eclipse (or NetBeans) plugin no matter what the productivity increase is.  I don't know if it's the limitations of developing for Eclipse, or the "Java community culture" or what.  I have not used IDEA.  I have used Rational Application Developer and MyEclipse and those both try to offer as many wizard-driven features as possible, because they know that's what paying customers want.  If it costs money, most Java developers will never be aware it exists.  I'm not saying Java developers on thedailywtf.com, I'm saying Java developers in general.

    .NET has the advantage of being in bed with Visual Studio, so they can come up with that kind of functionality and have everything work out great.  Sun tried to create a competitor to ASP.NET with Java Server Faces, with the idea that developers could create wizard tools to build websites in a Visual Studio-like fashion.  But it seems to be a failed experiment.  I think JSF could be successful as Sun intended if the Java community rallied around it, whatever faults it has, but it seems like most are happy to stick with Servlets/JSP and use Apache Struts as a framework if they feel they must have one.  As a result the free tools (i.e. the ones people actually use) are anemic at best.

    I'm not saying it's bad one way or another, and I don't mean to imply developers are cheapskates but this is the way it is as I see it.  I think it's a vicious cycle where Java developers look down on IDE automation and wizard tools because the ones available for Java are ineffective, plus it smacks of the "hated enemy" Microsoft.  As a result, nobody invests in those tools so they never improve very much, thus propagating the cycle.

    Also, if Visual Studio generates some code for a DataSet application, you know how that code is going to look for ANY such application and you know what the dependencies will be.  And you know it's ALWAYS going to work on VS and IIS because that's your environment.  Java developers fear vendor lock-in if they ever use any advanced IDE features, because they will include dependencies and jar files that will break if you ever move to any other IDE, application server, or JRE version.  Try using Rational Application Developer to develop a Java Web application, then deploying that application on JBoss.  Or try deploying a Liferay Portal Server portlet on WebSphere Portal (not sure how bad that is these days).  Integration and environment issues are, ironically, the constant enemy for Java Web applications.



  • @tster said:

    @djork said:

    Code generation is a good indicator of a flawed design. If your language of choice isn't malleable enough to avoid said generation, then you language is less than adequate for the task at hand. If the code generation is to work with an API (such as the one at my last job) then your API is poorly designed. I know it sounds like hyperbole, but it's true. Boilerplate == bad. Period.

    That being said, the "design flaws" that the necesary code generation reveal are usually not major (except in certain circumstances, like the API at my last job). I don't mind Windows Forms code, but I wish that there was something simpler behind the scenes for laying out forms.

    You couldn't be more wrong.  Please read "The Pragmatic Programmer" for more info on generated code.  

     

    PS.  I suppose you have never used a compiler?

     

    I think you two are thinking of different types of code generators.  And at least from the excerpt I read, the book seems to support both of you.


    Wizards and code generators tend to come in two types (or at least opposite ends of a continuum).  They type you seem to be thinking of is when you provide some intermediate form of input, and the generator spits out a black box that (hopefully) does what you want.  Like you said, pretty much a compiler.  In that case you're more or less creating a new language to handle something that's awkward in the original language.  Examples would be IDL compilers, JSP pages, XML bindings, etc.  In this case you're both right.  The generator exposes a shortcoming in the original language, but the generator is a good thing since it let's you use a language that's more suitable to the task at hand.

    The type of generator djork seems to be talking about is the type that generates boilerplate code (see many of the VC++ 6.0 MFC wizards).  This type doesn't generate a black box you can plug and play.  It generates code that is little better than automated cut & paste.  The generated code is too mixed in with your "real" code to be a good black box.  We make fun of that style of coding when it's done by hand, why should the wizard be excused?  Too often you end up having to maintain this code yourself (because regenerating again is difficult/impossible, or the generator didn't account for all your needs, or regenerating it would destroy your customizations, etc.).  If you don't understand what the generated code is doing (or if it's doing it in a sub-optimal way), it's going to cause you headaches down the line.

    I agree with djork to a point, and I don't think your book really disagrees (once again based on the excerpt from the site).  You wouldn't need the wizard/generator in the first place if your language/framework wasn't deficient in some sense (if it wasn't, it would be easier to just code what you want directly).  A generator might be the best way to overcome that deficiency, but that doesn't change the fact that it exist.

    Good wizards/generators will take take a form of input that's simpler than your original language and spit out a dependable black box.  If that's not possible, they at least spit out boilerplate that's simple, understandable, and not much different from what you would have coded by hand anyway (e.g. getter/setter generation in Eclipse).

    The problem is when a wizard/generator spits out a complex chunk of boilerplate that doesn't function as a black box.  If you don't understand what that boiler plate is doing it's going to cause you headaches in the future.  Sometimes worse than just writing the code yourself in the first place. 




  • @tster said:

    @djork said:

    Code generation is a good indicator of a flawed design. If your language of choice isn't malleable enough to avoid said generation, then you language is less than adequate for the task at hand. If the code generation is to work with an API (such as the one at my last job) then your API is poorly designed. I know it sounds like hyperbole, but it's true. Boilerplate == bad. Period.

    That being said, the "design flaws" that the necesary code generation reveal are usually not major (except in certain circumstances, like the API at my last job). I don't mind Windows Forms code, but I wish that there was something simpler behind the scenes for laying out forms.

    You couldn't be more wrong.  Please read "The Pragmatic Programmer" for more info on generated code.  

     

    PS.  I suppose you have never used a compiler?

    I was drunk when I wrote that, but I still think I'm right. I've been through the Pragmatic Programmer more than once. What I'm saying, at the core, is that code generation [i]reveals[/i] design flaws. For example: at my last employer they had a rather large and unwieldy framework and a set of tools that would generate code. The code it generated was compensating for:

    1. an inflexible language and framework design (C# 1.1, no generics, huge object hierarchies)
    2. an inflexible data access layer (generated C# and corresponding SQL en masse)
    3. a bizarre over-reliance on enumerations (where "magic numbers/strings" would actually, really, be appropriate)

    The best languages (and I'm not saying they are the best choice for every app, that's why I still use C# at my day job) let you redefine the language itself. Bottom-up and top-down design meet in the middle to form a small and flexible language/system that is just right for the task at hand, without relying on lots and lots of boilerplate code.

    Discussion: Code Generation Isa Design Smell



  • Code-generation and wizardly stuff is little more than a step up from auto-complete for for loops.

    The bigger it gets, the more you need/want to keep tabs on it, so there is a point of diminishing returns.

    You could abstract away whole pieces of "standard" functionality, but you'll be spending time changing the details because no two projects are the same, and sometimes you'd be better off having automated smaller parts of that functionality which are the same for any project, such as the aforementioned for loop completion, or grabbing generic data form the DB..



  • @dhromed said:

    Code-generation and wizardly stuff is little more than a step up from auto-complete for for loops.

    And illustrated here is my point that code generation is a design smell. for(int i = 0; i < x; i++) is exactly the kind of boilerplate that indicates a less-than-optimal* language. You would never feel the need to write a "snippet" for looping constructs in Ruby beyond inserting matching curly braces or "end" on your block.

    * No language is perfect. I still love using C for that bare-metal fun.



  • @djork said:

    @dhromed said:

    Code-generation and wizardly stuff is little more than a step up from auto-complete for for loops.

    And illustrated here is my point that code generation is a design smell. for(int i = 0; i < x; i++) is exactly the kind of boilerplate that indicates a less-than-optimal* language. You would never feel the need to write a "snippet" for looping constructs in Ruby beyond inserting matching curly braces or "end" on your block.

    * No language is perfect. I still love using C for that bare-metal fun.

    for seems far too generic a tool for the 90% of its usage: looping over a dense list.

    But still, it takes only a minimal change to step by 2, or by n, or by bla(), or start at non-zero, or -39, or break based on a second condition -- for whatever purpose. What code would have to be written that (in)elegantly modifies the .each and its equivalents to achieve those things in R (since you brought it up)?

    But maybe that's a silly question because every solution that requires a non-standard for in Cish languages will just use a different approach in R?



  • @dhromed said:

    @djork said:
    @dhromed said:

    Code-generation and wizardly stuff is little more than a step up from auto-complete for for loops.

    And illustrated here is my point that code generation is a design smell. for(int i = 0; i < x; i++) is exactly the kind of boilerplate that indicates a less-than-optimal* language. You would never feel the need to write a "snippet" for looping constructs in Ruby beyond inserting matching curly braces or "end" on your block.

    * No language is perfect. I still love using C for that bare-metal fun.

    for seems far too generic a tool for the 90% of its usage: looping over a dense list.

    But still, it takes only a minimal change to step by 2, or by n, or by bla(), or start at non-zero, or -39, or break based on a second condition -- for whatever purpose. What code would have to be written that (in)elegantly modifies the .each and its equivalents to achieve those things in R (since you brought it up)?

    But maybe that's a silly question because every solution that requires a non-standard for in Cish languages will just use a different approach in R?

    I hope I'm reading this right, but to do step by two in Ruby I'd do something like:

     

    module Enumerable
      def every_other (&block)
        each_with_index { |obj, i| yield obj if (i % 2 == 0) }
      end
    end
    

    Ta-da. Now anything that has an "each" iterator has an "every_other" iterator. Language extended.



  • @ObiWayneKenobi said:

    Can someone please enlighten me?   I want to learn best practices, so I can write code the "proper" way instead of learning bad habits

    Build a professional library. Get a personal copy of Code Complete by Steve McConnell. As far as I'm concerned, that's my coding bible. An appendix lists books that all software professionals should have. Some of them are old & out of print, but timeless.  Off hand here's a few of my favorites: The Mythical Man Month, Refactoring by Martin Fowler, Head First Design Patterns

     Read forums like WTF. Seeing the wrong way is a good way to learn.

    Find krapkode and rewrite it using principles as codified in Code Complete. A before and after picture is very enlightening.

    Pledge yourself to do the right thing, the right way, to the best of your ability, all the time.  Re-Read your old code and think about how it can be improved in light of what you learned since then.

    When it comes to testing, be a mean, heartless, relentless, thorough, SOB. To the code I mean. Especially your own. I have been very surprised at how coders sometimes seem to test to a "self fullfillinging" standard.

    Learn to use a testing tool like NUnit (for .NET). There are a bunch of test tools like this, generally referred to as "XUnit".  I just starting to use it recently and two things happened. First I instantly became a better tester and the code got better, and second you will make code changes with a high degree of confidence when you have your (previously passed) test code to verify.

     


Log in to reply