One Version

« Return to Article
  • Dion 2012-12-10 06:03
    There are worse ways to do that.
  • Steve The Cynic 2012-12-10 06:10
    Dion:
    There are worse ways to do that.

    Much worse. The fact that it is done by generated code is a consequence of the fact that Java lacks the preprocessor of C/C++, and thus cannot populate string variables with __DATE__. A pathetic mis-use of article space.

    1/10 could do almost infinitely better.
  • Jo 2012-12-10 06:15
    Actually, I'm doing essentially the same in Ant.
    I could be generating into a resource file instead of into a class file, but meh.
    Doesn't do any serious harm either, so you never come back and fix that, nor is it a real WTF. At best, a mini-WTF, a WTF-let :-)
  • OldHand 2012-12-10 06:17
    +1 yes.
    I do just this - only in Perl invoked from the Ant build script. Mine is a little more elaborate, in that it pulls a file revision list from Perforce, then builds a "Version.java" for compilation into the project. In this way, even if your configuration control is all to pot, you can always find out what source was used to generate a particular program. It can also generate a "Version.html" for dropping into the "web" directory of a Tomcat project, to give a web page with the build info on it.
    OP (I think) needs a gentle introduction into the idea of configuration control being your friend, not a chore.
  • Snakepants 2012-12-10 06:28
    Wait...what..this doesn't seem like a WTF. It seems like good practice to automatically tag builds.

    But maybe I've just gone too deep into old code and lost sight of the way back
  • Mike 2012-12-10 06:29
    The WTF is that this is a process known only to the lead architect and only accidentally discovered by Brian.
  • plasmab 2012-12-10 06:33
    Visual Studio does much the same.
  • Alex 2012-12-10 06:36
    This is a WTF people.. Using a .properties file included in the build would make a lot more sense.

    Code generation shouldn't be a part of your build unless it really is the only option.
  • Melnorme 2012-12-10 06:54
    At the very least, couldn't the script create TagFile.java directly?
  • Eric Jablow 2012-12-10 07:03
    No, the appropriate thing is to add information to a jar's MANIFEST.MF file, and to access the information in code through calls to java.util.Package. But that would require the programmers to actually think.
  • Remy Porter 2012-12-10 07:13
    Apparently the real WTF is that people think generating executable code as part of your build step is a good way to version a build.

    I don't care what language you're using- version information lives in a non-executable file. If you want code modules that read that file for ease of use, great. A -version flag is a great thing.
  • Cbuttius 2012-12-10 07:13
    I'm not expert enough to know how this is normally done in Java but it doesn't look the most WTF'y thing to me.

    I know code generation was very popular a number of years ago, especially in the days before generics and even to some extent in C++. That it is generated automatically rather than hand-built for every project obviously makes it less of a WTF.

  • Joe 2012-12-10 07:15
    OK I'm not enough of a Java guy to know The Right Way To Do It, but if all this ultimately does is print a string, couldn't this at least be simplified to merely generate the code that prints the string? You don't need all those static attributes and getters.

    As far as the concept of having your build script generate code, I don't have a fundamental problem with it. The more work you can automate, the better.
  • Erik 2012-12-10 07:27
    What's the WTF. Sure, doing it in a way native to the build system is preferrable if there is an easy way to do so, but there might not have been when this build system was created.
  • Remy Porter 2012-12-10 07:29
    Because generating code is always superior to generating a human-readable data-file that can be parsed by stock code?
  • jugis 2012-12-10 07:33
    Looks like a great way to sneak arbitrary code into someone else's program! :)

    That's what it's for right?
  • Padam 2012-12-10 07:43
    I used to have something like this before replacing it with Hudson -> Ant -> Manifest file generation with build/version/CVS details - works perfectly.
  • Meh 2012-12-10 07:45
    I do something similar with svn - I have a Perl program that gets the current build # and date, and generates a Java class with bean-like methods. Using Java to generate Java is overkill, but I can see this tag thing being written with the intent to expand it to svn later on.
  • bebert 2012-12-10 07:48
    Why a .properties? In a java JAR this info belongs to the META-INF/MANIFEST.MF file.
  • Steve The Cynic 2012-12-10 07:52
    Remy Porter:
    Apparently the real WTF is that people think generating executable code as part of your build step is a good way to version a build.

    I don't care what language you're using- version information lives in a non-executable file. If you want code modules that read that file for ease of use, great. A -version flag is a great thing.

    It's not versionning the build. It is identifying the build based on when it was built and by whom. That allows me to distinguish today's build from yesterday's build of the same sources (maybe I updated the compiler rather than the source code), and official builds (built by user "build") from unofficial builds (built by other users). If I change the compiler due to a fix for a bug, then I need to be able to say that all builds before date X must be treated with suspicion, and a build date stamp is the way to go. (No, it isn't the only way to do this, but there is a psychological advantage in having a date stamp rather than a build number. A date stamp is obviously tied to a particular real-world date, while a build number is not.)

    Doing it by a two-stage compilation process is a bit arcane, but not noticeably worse than e.g. processing lex/yacc inputs at build time or compiling .IDL files into proxy-stub DLLs for old-style DCOM projects. If you use the "manifest.mf" approach suggested by another poster, you replace code generation with manifest generation (since the contents of the file vary from build to build), but you don't really dissipate much of the WTF. (Assuming there's much WTF there in the first place...)

    Oh, and the "file" that contains the version information must be tightly bound to the code. A Windows .RC file, or the manifest.mf file in a jar, or the manifest information in a .NET assembly, or even a build-time-generated code file all serve this purpose. A random text file stashed alongside the executable code does not.

    A major chunk of WTF in the case of the article is that the process is not adequately documented, but that may be a failing of the submitter, in that he didn't seek the info. (Or it might really be undocumented, in which case the lead architect deserves a good slapping.)
  • Tankster 2012-12-10 07:55
    Alex:
    This is a WTF people.. Using a .properties file included in the build would make a lot more sense.

    Code generation shouldn't be a part of your build unless it really is the only option.


    why not?
  • TopTension 2012-12-10 08:08
    This is not a versioning system. Search for the word "version" in the code, you won't find it. It doesn't even assign a build number, which might be seen as the last digit of a version number.

    This tags builds with who built it and when. I also am not Java-savvy enough to know, if there are better ways to achive this, but it seems to get the job done and it is not a replacement for whatever proper way of assigning versions to the product.

    So what's the WTF exzctly?
  • Remy Porter 2012-12-10 08:08
    Because there should be a direct mapping of the code source control and the code in the build. By adding a code-generation step to the build process, you break that connection.

    Even Microsoft's tools generate code pre-compilation so that you actually check the generated code into source control. Now, in this case, someone was going back and checking these TagFile.java files back into source control, which is also pretty terrible, since they're going to be replaced every build, unless the process checks it back in automatically, and then you have this metadata file in source control that doesn't actually mean anything and argh.

    I oversee the build process in my company, and I would never want to see something like this.
  • Remy Porter 2012-12-10 08:16
    Date + builder sounds like a version to me, but that's needless pedantry. The issue isn't generating a file to document the build information, the issue is generating executable code to document the build information.

    Instead, every project should include a "ReadVersion" class, which handles request for build version information, and the build process should generate a text file which ReadVersion can parse.

    Now the code in source control matches exactly the code in the build, you've also got a human-readable fallback for build tagging.
  • caffiend 2012-12-10 08:18
    AFAIK TeamCity does something remarkably similar if you're using it's "Patch Assembly Version" feature on a C# project. I think it modifies the AssemblyInfo.cs before compilation.

    Though it seems like a goofy solution, it hasn't caused my team any trouble. It successfully stamps the build with the marketing department's arbitrary major version number and the version control system's revision number, which is a lot better than what happens without it.

    Addendum (2012-12-10 08:26):
    If you're from oldskool Windows Land, i hope you'd agree it's a lot better than using the venerable "stampver" tool and having to make sure that everyone set the version string to "000.000.000.000" to avoid sometimes corrupting the PE header.

    Oh the good old days

    Addendum (2012-12-10 08:41):
    Which, looking back on it would have failed catastrophically when we got up to Version 101.605.212.45289012. How short sighted of us.
  • silverwizard 2012-12-10 08:40
    It seems simpler to add the data to the file from the class that gets it. Rather than generate an executable to give the information out. One of the files is bloat.
  • caffiend 2012-12-10 08:57
    I don't think there is actually a good solution to this problem on any platform. Since I'm not experienced with commercial software development on platforms other than windows, I won't pretend to be an expert. AFAIK, no other platform attempts to embed version information in an executable in a standardized way (but i could be wrong, but nobody has said so yet).

    On windows, the PE header uses a string to store the version information. The length of the string is determined at compile time, and can it's contents can be modified after the fact, so long as the resultant string is not bigger than the string that was dimensioned at compile time. If it is bigger, random bad stuff happens when your version string overwrites something useful in the bytes just after it (but not always, depending on whether or not your version string ended on a 4 byte boundary it is padded with zeros).

    If you're using .NET, there are two version numbers (who knows why), the assembly version number (which is a .NET metadata thing) and the PE version number, which sits in the traditional spot in the PE header, with all the aforementioned problems. The two are completely disconnected and can be different (again, why?). The OS sometimes looks at the PE version number and sometimes looks at the assembly version number depending on whether you're trying to install it in the GAC or whether or not you're trying to get MSI to update the installed version of a dll side-by-side to the application (again, why?).

    In .NET land, Microsoft allows the developer to set the version number in code using the AssemblyInfo.cs file, which is auto-generated with visual studio projects... Awesome, you set the attribute in the code and all the version numbers come out the same.

    So the most pragmatic solution for an automated build process seems to be to dynamically change this version number. Whats the big deal?

    This looks like a java based attempt at the same, except it isn't really needed if all it's trying to do is output some text in response to being called with the "--version" argument.

    So i guess that is TRWTF?
  • Steve The Cynic 2012-12-10 09:08
    Remy Porter:
    Because there should be a direct mapping of the code source control and the code in the build. By adding a code-generation step to the build process, you break that connection.

    Even Microsoft's tools generate code pre-compilation so that you actually check the generated code into source control. Now, in this case, someone was going back and checking these TagFile.java files back into source control, which is also pretty terrible, since they're going to be replaced every build, unless the process checks it back in automatically, and then you have this metadata file in source control that doesn't actually mean anything and argh.

    I oversee the build process in my company, and I would never want to see something like this.

    Um, but there is a 1-to-1 correspondence between what's in source control and what's in the built code. It's just more indirect than normal.

    "Indirect"? Indeed. Unless you code directly in binary machine code or JVM byte code, there's an indirect relationship between the input files and the final release package. A collection of .java files is processed by javac, and the .class files are bundled together with appropriate metadata and other resources to produce one or more .jar files. We've just modified the process so that one of the inputs to one or other part of the process is generated before javac and/or the .jar builder gets hold of it. This allows the embedding of per-build variable data without having to check that one-time-only data into *source* control. In C or C++ you ca generate build date/time information by using the predefined __DATE__ and __TIME__ macros, and therefore don't need to do this sort of trickery. You could do something similar in a Windows .rc file, since that is also processed using the same preprocessor.

    But either way, you have an invariant part (GenerateTagFile.java in the article) that generates per-build-variable data in a way that gets it included in the build without having to check it in for every official build. As others have mentioned, there may be better ways of doing this in the particular case of Java, but the fundamental issue remains: you want build date/time/culprit data in the build process's output, and you don't want to have to check that data into the process every time. You have limited choices.

    Another approach is to have a two-stage build process that does a clean checkout from a suitably-encoded source control label (or other tagged version-set), and generate a build-label-file as part of the check-out process. Once that's done, you proceed to the actual build.

    The end result is the same. You know (or can derive) the date, time, and culprit of the build, and you have source-control information on which versions of what files were included. So in effect, we are merely arguing about the exact nature of the build-label-file.
  • Xarthaneon the Unclear 2012-12-10 09:12
    Dion:
    There are worse ways to do that.


    Yeah - a better way may involve pushing the data fields and methods down to a base class, and having each individual tags.java file inhertit from that class, but with the constructor providing the location-specific details for each subclass.

    So, a quasi-WTF. The architect could've architected this bit better.
  • Ben Jammin 2012-12-10 09:14
    If you didn't have code generating code, you would not have the potential for a glitch to suddenly give your computer artificial intelligence.
  • asdf 2012-12-10 09:22
    what happened to Nagesh?
  • Steve The Cynic 2012-12-10 09:24
    asdf:
    what happened to Nagesh?

    Speak not the name of the Spawn.
  • Unicorn #2816 2012-12-10 09:25
    Got bored, probably. People stopped biting.
  • Sociopath 2012-12-10 09:37
    I just solved this problem today in one of my projects. With Maven it's deceptively simple. Add to your pom.xml
    <properties>
    
    <build.timestamp>${maven.build.timestamp}</build.timestamp>
    <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
    </properties>

    <build>
    <resources>
    <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering>
    </resource>
    </resources>
    </build>

    Then just make sure you have some properties file:
    # build.properties
    
    build.timestamp=${build.timestamp}

    Load the properties file in your code, and access the build timestamp at runtime.
    So easy; if you're building with Maven.
  • Pete 2012-12-10 09:59
    Seriously how hard is it to use a tool like Hudson and generate a Manifest with this information.
  • Slartibartfast 2012-12-10 09:59
    As other people have already pointed out, the way to do this "by the book" in Java is to write a proper MANIFEST.MF file with any kind of version information you want it to have. That can be read out when the software is running in order to provide version info to the user, and most of all it can also be read out by other tools you may use to manage your software, like deployment tools and stuff, since there's a number of standard elements in MANIFEST.MF files which define - among other things - a standard way to tag version numbers and build dates.

    If you even start to modularize your software, so it doesn't all end up in one big jar, but multiple of them, which may even be built individually and used in various combinations, you'll really start to enjoy having a proper version number injection in your build process which tags each single module/jar of your software with version and build numbers, dates etc. - one of the hells to be avoided on the path to modularization is version hell, in which you don't really know which different versions of your stuff you've got running together and thus can't track problems down to specific versions of modules. MANIFEST.MF files, properly used, enable you to provide detailed versioning information for each of your build artifacts individually; you may even add automatic checks to ensure that only specific versions of modules can actually run together, such as only those with the same major and minor version number.
  • QJo 2012-12-10 10:05
    The real WTF, then, is:

    import java.util.*;

    when it really should be invoking just the classes required.

    I would also take issue with use of "Hashtable" - it ought to HashMap, using Map as the interface. Anything else is simian.

    Oh, and somehow the code generator knows how to generate that first line using sb.append("importjava.util.*;\n\n"); ...
  • Doodpants 2012-12-10 10:15
    TRWTF is storing the date/time stamps as strings, instead of using Calendar instances.
  • Sutherlands 2012-12-10 10:20
    caffiend:
    I don't think there is actually a good solution to this problem on any platform. Since I'm not experienced with commercial software development on platforms other than windows, I won't pretend to be an expert. AFAIK, no other platform attempts to embed version information in an executable in a standardized way (but i could be wrong, but nobody has said so yet).
    As already has been said, for Java, you use the manifest file.

    caffiend:

    If you're using .NET, there are two version numbers (who knows why), the assembly version number (which is a .NET metadata thing) and the PE version number, which sits in the traditional spot in the PE header, with all the aforementioned problems. The two are completely disconnected and can be different (again, why?). The OS sometimes looks at the PE version number and sometimes looks at the assembly version number depending on whether you're trying to install it in the GAC or whether or not you're trying to get MSI to update the installed version of a dll side-by-side to the application (again, why?).
    One is updated any time you update the DLL, the other is updated only when you make a breaking change. When you're installing it in the GAC, if the second number is the same, it will overwrite the old version and the clients will automatically begin using it. If that number is different, it will install it side-by-side and clients will use the version they were compiled against. I'm sure you can understand the need for a version number separate from this...
  • trtrwtf 2012-12-10 10:24
    Hey, at least they used a StringBuffer to glom that String together...

  • PedanticCurmudgeon 2012-12-10 10:25
    asdf:
    what happened to Nagesh?
    Apparently, based on all the not-a-WTF posts here, Nagesh has been assimilated into the collective unconscious.
  • Steve 2012-12-10 10:54
    I'm so proud that my method doIt() has survived so many companies over so long a time. It's coming up on 20 years.

    I never worked on Java though. Are you sure this wasn't doit.bat? :)
  • iWantToKeepAnon 2012-12-10 11:37
    The real WTF is when I had to move from CVS to ClearCase and found that there was no such thing as tag substitution. Really, WTF? So everyone is left to reinvent that particular wheel.

    This isn't a WTF, just more code snobbery.
  • Kasper 2012-12-10 11:37
    Why does so many people want the version information to be in a separate file? If the version information doesn't get included in the executable being build, I don't see what value it adds?

    If you distribute the version number and executable as separate files, it is just too easy to replace the executable but keep the version number the same.
  • stray 2012-12-10 12:11
    You can have tag substitution in ClearCase by using suitable triggers.
    The problem is: What kind of information do you want to embed into your sources? Considering the crazy flexibility of ClearCase views (hint: Config Specs), you will have a hard time just to define a manageable and useful amount of version information.
  • Fedaykin 2012-12-10 12:17
    Unless you have a _very_ good reason (see: AI work, working in a language with insufficient abstraction capabilities, etc.), writing code generating code means you're doing it WRONG.

    Especially if it's for something as trivial as tagging a build, which is a solved problem.
  • PseudoBovine 2012-12-10 12:26
    Kasper:
    Why does so many people want the version information to be in a separate file?


    Overzealous application of "good design principles".

    One practice that is normally a good thing is the separation of code and data. For example, if you ran across a program that had to be recompiled every time the host IP address changed, you'd rightly consider that a WTF. If there's information that can vary, it's almost always a good idea to factor that out into a configuration file, database or similar.

    That's the thought process. "The versioning information changes constantly. 'Best practices' would be to generalize it out into some sort of data storage system." - Again, *usually* this would be the right thing to do, but as you mention, the tight coupling between the version information and the actual code is a highly desired feature.

    In short, blindly following "best practices" isn't always for the best.
  • Chris L 2012-12-10 12:54
    As a not-a-programmer, I enjoy the discussions around the borderline WTFs more than anything on this site. It seems to me that this type of article exposes philosophical WTFery rather than objectively bad code.

    How closely should you couple build information with your compiled code? If you're going to put the name and date in, why not your compiler version? Or a representation of your entire build environment? Why not include what you had for breakfast last Thursday?

    It would be interesting to hear the reasons why this system was implemented in this precise way.


    CAPTCHA: decet (cet phasers to kill, then decet them before writing your report)
  • Bananas 2012-12-10 13:06
    Does nobody place any value on being able to reproduce an older version of the executable from source control?
  • Blort 2012-12-10 13:18
    Unless you have a _very_ good reason (see: are actually some kind of god), making blanket statements about methods you prefer not to use means you're doing it WRONG.

    I can think of several good uses for code generation. This isn't exactly one of them, but you don't have to be doing AI research to save yourself time and take human error out of the equation.
  • BillClintonIsTheMan 2012-12-10 13:31
    Bananas:
    Does nobody place any value on being able to reproduce an older version of the executable from source control?


    Yes, as I read it this is more of a "blame" scenario.

    This dev team probably has little or no control over package distribution/delivery, and this is how they identify who sent what to where and when.
  • Tom 2012-12-10 13:51
    TRWTF is not using reflection.
  • trtrwtf 2012-12-10 13:56
    Chris L:
    As a not-a-programmer, I enjoy the discussions around the borderline WTFs more than anything on this site.



    WTF?????
  • qbolec 2012-12-10 14:03
    PseudoBovine:
    Kasper:
    Why does so many people want the version information to be in a separate file?


    Overzealous application of "good design principles".

    One practice that is normally a good thing is the separation of code and data. For example, if you ran across a program that had to be recompiled every time the host IP address changed, you'd rightly consider that a WTF. If there's information that can vary, it's almost always a good idea to factor that out into a configuration file, database or similar.

    That's the thought process. "The versioning information changes constantly. 'Best practices' would be to generalize it out into some sort of data storage system." - Again, *usually* this would be the right thing to do, but as you mention, the tight coupling between the version information and the actual code is a highly desired feature.

    In short, blindly following "best practices" isn't always for the best.


    but, but, build version changes precisely every time I compile a program, which keeps the build-to-change ratio at 1:1 level, so there is no benefit in separating the two. It's not like with the hardcoded host IP example where the ratio was more like 1:X :))
  • vic 2012-12-10 14:15
    I guess everyone missed the part where it says the code does not compile until this file has been generated, and also the copy-pasting of the GenerateTagFile.java in all projects.
  • qbolec 2012-12-10 15:06
    vic:
    I guess everyone missed the part where it says the code does not compile until this file has been generated, and also the copy-pasting of the GenerateTagFile.java in all projects.

    Actually I was more puzzled by the part where it says that the file was missing, but was also in the repo at the same time. So... was it missing, auto-generated, copy&pasted, or simply checked out?
  • jay 2012-12-10 16:29
    Are there better ways to do it? Sure. But my standards for deciding if code is screwed up are:

    1. Does it work? This looks like it should. Pass.

    2. Is it reasonably understandable by other programmers? Looks like. Pass.

    3. Is it easy to maintain? Yes. Pass.

    4. Is it efficient? Not the best, but shouldn't be awful. Pass, maybe with some minor reservations.

    5. Is it robust, i.e. unlikely to fail? Might be some grounds for criticism here. Depending on how the build scripts are written, maybe a failed build would end up being mislabeled, and that could interfere with problem resolution. Maybe.
  • Kiwi 2012-12-10 16:39
    Bananas:
    Does nobody place any value on being able to reproduce an older version of the executable from source control?

    Well the lead developer a few jobs ago refused to allow build dates/times in binaries for an embedded system so the historical rebuilds matched exactly. Unfortunately I'd felt that the additional info was better!
  • jamesn 2012-12-10 17:05
    jay:
    Are there better ways to do it? Sure. But my standards for deciding if code is screwed up are:

    1. Does it work? This looks like it should. Pass.

    2. Is it reasonably understandable by other programmers? Looks like. Pass.

    3. Is it easy to maintain? Yes. Pass.

    4. Is it efficient? Not the best, but shouldn't be awful. Pass, maybe with some minor reservations.

    5. Is it robust, i.e. unlikely to fail? Might be some grounds for criticism here. Depending on how the build scripts are written, maybe a failed build would end up being mislabeled, and that could interfere with problem resolution. Maybe.


    2. Is it reasonably understandable by other programmers? Not really. I mean, who expects that sort of thing? See also #5.

    3. Is it easy to maintain? No! Fail! The "code generator" file and the associated build steps need to be copied to every project that uses that mechanism.

    Overall I rate this as mild or head-scratcher on the WTF scale.
  • -- 2012-12-10 17:09
    Chris L:
    I enjoy the discussions around the borderline WTFs more than anything on this site. It seems to me that this type of article exposes philosophical WTFery rather than objectively bad code.



    Yeah I also like the ones that are questionably wtf-worthy. Mostly because I like reading the best practice discussion. I come to this site to possibly get a laugh and possibly learn something.

    CAPTCHA: ideo - a male idea
  • Kasper 2012-12-10 18:46
    Kiwi:
    Well the lead developer a few jobs ago refused to allow build dates/times in binaries for an embedded system so the historical rebuilds matched exactly. Unfortunately I'd felt that the additional info was better!
    I believe both points of view are valid. That does mean there are two conflicting goals and one need to relax one of the two goals just a little bit in order to resolve that conflict.

    The compromise I'd recommend is to have the automatic build system include relevant information including date in the targets that are build. However there then need to be a way to manually override the strings when you want to do a historic build and have an exact match. By default builds made outside of the automatic build system should be clearly labelled in a way that can distinguish development builds from release builds.

    Reproducible builds are good for certain validation of builds. For example you can have two different people look at the source being build and have both confirm that those executables are really build from that source.
  • Andrew 2012-12-10 19:22
    I was thinking the same thing and that perhaps TRWTF was that the code wouldn't compile in this instance because it required the file that it would generate, if it successfully compiled. The workaround was a copy paste from elsewhere.
  • Callin 2012-12-10 19:22
    That's nothing. Wait until you meet GenerateGenerateTagFile.java
  • Evan 2012-12-10 19:55
    Kasper:
    Why does so many people want the version information to be in a separate file? If the version information doesn't get included in the executable being build, I don't see what value it adds?

    If you distribute the version number and executable as separate files, it is just too easy to replace the executable but keep the version number the same.

    That was my reaction too. (Things like the Manifest file that would get built to the same JAR don't count as separate.)

    I can't claim to be an expert, but advice like version information lives in a non-executable file. If you want code modules that read that file for ease of use sounds like exactly the wrong thing to do to me.
  • Jared Kells 2012-12-10 21:03
    Doesn't seem like much of a WTF to me.

    For the naysayers what is the "correct" way to achieve this? I am genuinely curious.

    In .NET land I update AssemblyInfo.cs and the wix installer xml files on the build server using NANT before compilation.

    It's virtually the same thing.
  • Norman Diamond 2012-12-10 23:14
    Callin:
    That's nothing. Wait until you meet GenerateGenerateTagFile.java
    To build yacc, first code the grammar for yacc in yacc, and pass it through yacc. That produces a C program, which you pass through a C compiler that compiles C compilers to C programs that compile C, but first you need to compile the C program that compiles yacc to C, and then compile the resulting C to produce a program that compiles yacc.

    I don't think I can parse that.
  • Bulb 2012-12-11 02:59
    Remy Porter:
    Because there should be a direct mapping of the code source control and the code in the build. By adding a code-generation step to the build process, you break that connection.

    Than you'd have to program in machine code. Because compilation and code-generation are the same thing. Remember, when compiling C, the preprocessor first generates preprocessed C, than the compiler writes out Assembly, still human-readable and human-writable language and than the assembler simply recodes that in the binary form. And early C++ and ObjC compilers compiled to C, so just inserting another step into that chain. And many other compilers just do the same; they generate another language normally used for programming and chain to it's respective compiler.
    Remy Porter:
    Even Microsoft's tools generate code pre-compilation so that you actually check the generated code into source control...

    Generated files should not be checked in version control. It does not matter whether they are "code". Assembly is also "code" and you don't consider checking that in.
  • Bulb 2012-12-11 03:00
    Remy Porter:
    Because generating code is always superior to generating a human-readable data-file that can be parsed by stock code?

    Code is not human readable? Or not parsed by stock code (the compiler)?
  • Steve The Cynic 2012-12-11 05:00
    jamesn:
    jay:
    Are there better ways to do it? Sure. But my standards for deciding if code is screwed up are:

    1. Does it work? This looks like it should. Pass.

    2. Is it reasonably understandable by other programmers? Looks like. Pass.

    3. Is it easy to maintain? Yes. Pass.

    4. Is it efficient? Not the best, but shouldn't be awful. Pass, maybe with some minor reservations.

    5. Is it robust, i.e. unlikely to fail? Might be some grounds for criticism here. Depending on how the build scripts are written, maybe a failed build would end up being mislabeled, and that could interfere with problem resolution. Maybe.


    2. Is it reasonably understandable by other programmers? Not really. I mean, who expects that sort of thing? See also #5.

    3. Is it easy to maintain? No! Fail! The "code generator" file and the associated build steps need to be copied to every project that uses that mechanism.

    Overall I rate this as mild or head-scratcher on the WTF scale.


    2. Is it reasonably understandable by other programmers? Not really. I mean, who expects that sort of thing? The fact that it is unexpected is not automatically an obstacle to understanding.

    3. Is it easy to maintain? Yes, but you must take some steps to ensure it is reliably easy to maintain. You have to first realise that the tag file generator is part of the build system, not part of the body of source code, and should be deployed and launched as such. The rest more or less follows from there.

    Oh, and remember Steve The Cynic's rule:

    90%[1] of what we do as programmers is communicating with other people.

    [1] It might not be exactly 90%, but the fraction is nevertheless close to 100%.

    We do this through email, talking, the source code, and even documentation. In the context of this discussion, STCrule means that we should have documents that describe all this. But that's another battle to fight.
  • Roland 2012-12-11 05:08
    Our build process here generates a timstamp file that has the date, time and level information in the filename. The file is automatically included in the META-INF directory of every JAR, WAR or EAR file that is generated. That way, I can use 'jar' or 'zip' to get the version information from the command line, without first extracting a MANIFEST.MF and then looking at its content.
    Of course that is not the best solution if you want a '"-version" switch that prints the information, because then you'd want to know the filename in advance. For that, I'd probably prefer the MANIFEST.MF solution.

    (captcha: dolor - oh these pains...)
  • Gibbon1 2012-12-11 07:56
    Kiwi:
    Bananas:
    Does nobody place any value on being able to reproduce an older version of the executable from source control?

    Well the lead developer a few jobs ago refused to allow build dates/times in binaries for an embedded system so the historical rebuilds matched exactly. Unfortunately I'd felt that the additional info was better!


    I wrote a utility that will read in a hex file and it's matching .elf file, then update the hexfile with list of symbols and strings, then write it out into a ./images directory. The modified hexfiles get checked in with the code. That allows you to add compile dates, revision numbers, and checksums without modifying source files and recompiling. One key thing is it does not reformat the hexfile, so you can use diff, to verify changes.
  • Svensson 2012-12-11 10:33
    jamesn:

    2. Is it reasonably understandable by other programmers? Not really. I mean, who expects that sort of thing? See also #5.


    I don't know what your problem is, but I understood it easily. The biggest barrier to my understanding was that I was constantly looking for the WTF, but I never found it.


    3. Is it easy to maintain? No! Fail! The "code generator" file and the associated build steps need to be copied to every project that uses that mechanism.


    This is intentional. The code generator and associated steps are part of the project so that they do not result in an additional external dependency. You would explicitly customize it for each project as the project demands.

    Remember, the point of code re-use is to reduce work. Sometimes copying and making local mods really is better than using a library.


  • Evan 2012-12-11 10:42
    Bulb:
    Generated files should not be checked in version control. It does not matter whether they are "code". Assembly is also "code" and you don't consider checking that in.

    99% of the time I agree with you, but I think there are very occasional exceptions if for some reason you think that the generation is "too hard." For instance, I've checked in files that are generated by an obscure third-party tool that probably no one would have if not for the project. Checking in the generated files makes it so you don't even need it for that project if you don't want it.

    I agree it's not an ideal solution, but I think the benefits of making the repository much more of a "one-stop-shop" for what you need to build makes it worth it. As with every rule (probably including this one :-)) there are no completely hard and fast rules.
  • Your Name 2012-12-11 12:34
    "Brian’s brain break" broke my brain.
  • Coyne 2012-12-11 22:00
    I'm confused: Why is a two-stage process even needed? Why does the build process not just build the TagFile class, instead of building a TagFileBuilder class which is then run to build the TagFile class? After all, to build the former, the build process had to have all the information needed to build the latter, the way it's building it.

    My brain hurt.

    I'm reminded of those nested Russian dolls. Does he need a builder to build the builder of the builder of the tag file? Hmmmm....
  • Lacho 2012-12-12 00:17
    Y'know, I actually think that's pretty cool.
  • AN AMAZING CODER 2012-12-13 00:29
    Alex:
    This is a WTF people.. Using a .properties file included in the build would make a lot more sense.

    Code generation shouldn't be a part of your build unless it really is the only option.


    Properties files can be easily changed by humans.

    I'm guessing the point of this somewhat hacky build process is to have trustable build information available to the program at run time. Perhaps for some reporting and debugging purpose.

    I highly doubt your operating system's build information is stored in text somewhere.

    Either way, it's an eyebrow raiser at best, not a wtf.
  • AN AMAZING CODER 2012-12-13 00:40
    Remy Porter:
    Because there should be a direct mapping of the code source control and the code in the build. By adding a code-generation step to the build process, you break that connection.

    Even Microsoft's tools generate code pre-compilation so that you actually check the generated code into source control. Now, in this case, someone was going back and checking these TagFile.java files back into source control, which is also pretty terrible, since they're going to be replaced every build, unless the process checks it back in automatically, and then you have this metadata file in source control that doesn't actually mean anything and argh.

    I oversee the build process in my company, and I would never want to see something like this.


    I agree that checking build-generated files into source code is a bad idea. But that's not what this article expresses. It expresses that generating code at build time is a bad idea without any context around the reason why.

    If a requirement was runtime availability of the build-time information that could not be easily modified by a malicious end-user, how would you accomplish it?

    You're going to say "you can use a hex editor on compiled classes anyway" or something like that, but that's outside of my definition of "easily".
  • Sultan 2012-12-17 07:56
    Good job trying to reinvent XML.
  • Anon 2012-12-17 11:40
    The javac compiler lacks a preprocessor, sure, but one could easily be added to the build scripts or other parts of the system if needed. For example, the following code works with CVS:

    private String revision = "$Revision: $";


    When CVS handles the file, it automatically fills that with the correct revision (and updates it again later). A similar system would be very easy to create and use with for example Ant scripts.
  • W. 2012-12-20 09:08
    PseudoBovine:
    For example, if you ran across a program that had to be recompiled every time the host IP address changed, you'd rightly consider that a WTF.


    *cough* oracle enterprise manager *cough*
  • Rich 2012-12-21 18:35
    This kind of thing is practically encouraged in the .NET stack, although usually at design time rather than build time: T4 Templates.
  • instigator 2013-01-03 14:11
    Oh boy, another file to keep up with during install.