32

In our mostly large applications, we usually have a only few locations for "constants":

  • One class for GUI and internal contstants (Tab Page titles, Group Box titles, calculation factors, enumerations)
  • One class for database tables and columns (this part is generated code) plus readable names for them (manually assigned)
  • One class for application messages (logging, message boxes etc)

The constants are usually separated into different structs in those classes. In our C++ applications, the constants are only defined in the .h file and the values are assigned in the .cpp file.

One of the advantages is that all strings etc are in one central place and everybody knows where to find them when something must be changed.

This is especially something project managers seem to like as people come and go and this way everybody can change such trivial things without having to dig into the application's structure.

Also, you can easily change the title of similar Group Boxes / Tab Pages etc at once. Another aspect is that you can just print that class and give it to a non-programmer who can check if the captions are intuitive, and if messages to the user are too detailed or too confusing etc.

However, I see certain disadvantages:

  • Every single class is tightly coupled to the constants classes
  • Adding/Removing/Renaming/Moving a constant requires recompilation of at least 90% of the application (Note: Changing the value doesn't, at least for C++). In one of our C++ projects with 1500 classes, this means around 7 minutes of compilation time (using precompiled headers; without them it's around 50 minutes) plus around 10 minutes of linking against certain static libraries.
  • Building a speed optimized release through the Visual Studio Compiler takes up to 3 hours. I don't know if the huge amount of class relations is the source but it might as well be.
  • You get driven into temporarily hard-coding strings straight into code because you want to test something very quickly and don't want to wait 15 minutes just for that test (and probably every subsequent one). Everybody knows what happens to the "I will fix that later"-thoughts.
  • Reusing a class in another project isn't always that easy (mainly due to other tight couplings, but the constants handling doesn't make it easier.)

Where would you store constants like that? Also what arguments would you bring in order to convince your project manager that there are better concepts which also comply with the advantages listed above?

Feel free to give a C++-specific or independent answer.

PS: I know this question is kind of subjective but I honestly don't know of any better place than this site for this kind of question.

Update on this project

I have news on the compile time thing:
Following Caleb's and gbjbaanb's posts, I split my constants file into several other files when I had time. I also eventually split my project into several libraries which was now possible much easier. Compiling this in release mode showed that the auto-generated file which contains the database definitions (table, column names and more - more than 8000 symbols) and builds up certain hashes caused the huge compile times in release mode.

Deactivating MSVC's optimizer for the library which contains the DB constants now allowed us to reduce the total compile time of your Project (several applications) in release mode from up to 8 hours to less than one hour!

We have yet to find out why MSVC has such a hard time optimizing these files, but for now this change relieves a lot of pressure as we no longer have to rely on nightly builds only.

That fact - and other benefits, such as less tight coupling, better reuseability etc - also showed that spending time splitting up the "constants" wasn't such a bad idea after all ;-)

Update2

Since this question still receives some attention:
Here is what I've been doing in the past few years:

Put every constant, variable, etc exactly in the scope that is relevant for it: If you use a constant only in a single method, it is OK to define it in that method. If a single class is interested in it, leave it as a private implementation detail of that class. The same applies for the namespace, module, project, company scope. I also use the same pattern for helper functions and the like. (This may not apply 100% if you develop a public framework.)

Doing this increased reusability, testability and maintainability to a degree where you not only spend less time compiling (at least in C++), but also less time on bugfixing, which leaves you more time for actually developing new features. At the same time, developing these features will go faster since you can reuse more code more easily. This outweighs any advantage the central constants file might have by a magnitude.

Take a look at especially the Interface Segregation Principle and the Single Responsibility Principle if you want to know more.

If you agree, upvote Caleb's answer since this update is basically a more general take on what he said.

  • 2
    personally I wouldn't have UI title or message strings in constants at all. I'd have them in app.config – jk. Apr 19 '12 at 12:06
  • 1
    I kinda like how you are doing it now - I understand your disadvantages but we might just have to deal with that. – bigtang Apr 19 '12 at 12:42
  • 1
    I've seen exactly the same problem in a large Java project... One huge "constants" interface, change anything in it and wait 15 minutes for eclipse to recompile. I'm with Caleb: group the constants where they naturally belong, close to the code that uses them. Keeping them separate because they're constants is a useless OCD exercise. – Michael Borgwardt Apr 19 '12 at 20:11
  • The tight coupling is not a problem, because that's what you actually want. You want one change in your constants file affect possibly lots of source files. (Of course you have other problems as well). – gnasher729 Aug 24 at 22:15
  • @gnasher729 that is only true if a lot of classes use the same constant. You'd never want classes to be tightly coupled to constants they are not related with. It might not seem a problem at first until you try reusing it in another project without copying it or running isolated tests – Tim Meyer Aug 25 at 10:44
29

Constants that are specific to a class should go in that class's interface.

Constants that are really configuration options should be part of a configuration class. If you provide accessors for the configuration options in that class (and use them in place of the constants elsewhere), you won't have to recompile the whole world when you change a few options.

Constants that are shared between classes but which aren't meant to be configurable should be reasonably scoped -- try to break them out into files that have particular uses so that individual classes only include what they actually need. This again will help reduce compile times when you change some of those constants.

  • 1
    In case you are interested: I updated my question with what I have achieved, following your answer and others – Tim Meyer Jun 5 '12 at 14:32
6

I'd say simply that you want to split your huge constants class into many smaller files, one per form for example. This ensures you don't have such a huge dependency on the constants file, so adding or updating a string would not then require a total recompile. You can still store these files in a central location, but (eg) have 1 file with constants for each dialog, suitably named. Then you can only include those files in the relevant dialog files, which cuts down the recompilation massively.

I'd also suggest you use something like GNU GetText utilities to handle the strings, it's designed for translation, but works just as well for simply changing the text to something else. You could put them in a strings resource, but I find them to be more difficult to work with as they're keyed by ID, the GetText utils are keyed by an original string - makes things very easy to develop.

  • I might give that a shot. As the constants class with titles etc is split into several structs, I could maybe do one class per struct as a beginning. Not sure about the GNU thing, we usually don't want to change our strings at runtime, just during development time. We are using Qt's translation mechanism however, in case we have to translate to another language in future. – Tim Meyer Apr 19 '12 at 16:16
  • In case you are interested: I updated my question with what I have achieved, following your answer and others – Tim Meyer Jun 5 '12 at 14:33
2

Note: I am not a C++ developer... but here is my thought: You need to consider following @jk's comment about the difference between using configuration files. In DotNet, there are resources file that is used to store such information. In Windows Forms, a resource file is maintained from VS for each form.

I don't see a value for a constant to be placed outside its scope of use unless it is a global constant that must be shared. As you mentioned this will be difficult to maintain during development at least. Also, you may get name clashes. Another thing is that it might be difficult to know who is using a given constant.

Now if you want non-programmer to review information then, for GUI, you capture the screen for them. If you want them to review data table entries, you could export the data to Excel or something similar.

If you still want to go with a centralized location approach and you want to place all your constants in one big file, each developer may use a shared file that is updated at the end of each interval to a central file. The data will come from individual files used in development. This can be easily automated or done manually. However, as I said it is probably a risk you don't have to take.

2

There is no general solution. Ask yourself about performance, usability, security and lifecycle of a constant.

The closer they are defined to their scope the higher the performance.

The more they are grouped logically and outside their scope, the higher the reusability.

The less accessible the costants are, the higher the security.

The higher the lifetime of a constant, the less it cares of where you put it for usablity.

A constant like a version number will be defined in some kind of manifest. An error code of a error function will be defined inside the class. The error code is likely something with a high lifetime (= almost never changes). Putting it in a constant file just spams the file with unnecessary stuff.

The less the constant has the character of a constant but a variable (like version number) the more you can put it outside. The less variable the constant is, so the more constant it is, the more it should placed inside it's scope. During debugging it make sense to place it outside to reduce compilation time.

However, your initial problem is compilation time. So the question is whether you ask the right question. If the compilation time of your application is too high, you should better think of a way to make it more modular so that parts work independet from each other. Partially compile it and test your stuff independendly. If your unit tests are properly done and fullblown (which is a lot of work actually), then you can pretty easily shift stuff around without having to worry about that. And then the question gets a totally different drive.

1

I would suggest putting all of these constants into some sort of configuration file. For Java applications, we usually use .properties files, a simple text with each line formatted as "(key) = (value)". Example

MainPanel.Title = Welcome to our application
DB.table.users = TBL_USERS
logging.filename = application.log

You then load this file at runtime, populate a cache that lets you look up a key and get back a value. When you need a constant you then query the cache. You will still need to have your keys somewhere, and the cache will need to be globally accessible, but when you change the actual values of the constants, no recompile is necessary, it should be possible to just re-start the app (or if you really want to get fancy, have multiple .properties files and caches and give the application the ability to reload a cache at run-time).

For an implementation, I found this SO question: https://stackoverflow.com/questions/874052/properties-file-library-for-c-or-c (it was the first hit on a Google search - I haven't actually used this software myself).

  • For the C++ projects, we only need to recompile the constants file if we change a value. This is because values are assigned in a .cpp file. However adding/removing/renaming/moving a constant still requires a full rebuild – Tim Meyer Apr 19 '12 at 16:05
  • @TimMeyer: If you split the constants to multiple files, adding/removing a constant would only affect the files that depend on that particular file, correct? – FrustratedWithFormsDesigner Apr 19 '12 at 16:08
  • Correct. The main problem is that if I suggest that, people tend to mention one of the things I listed as "advantages" get lost – Tim Meyer Apr 19 '12 at 16:14
  • However, I haven't actually thought about putting several constants files in the same place – Tim Meyer Apr 19 '12 at 16:14
  • +1. @Tim Meyer: For this purpose, compile-time checking costs much more than it saves. Besides, what are you going to do if you need to internationalize? – kevin cline Apr 19 '12 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.