Questions about Coding Practices and Scalability

Greetings,

I have a couple (sets of) questions I am hoping people can help me with. The first one is merely asking whether or not my coding habits are intelligent, or if I shouldn’t apply them so universally. At the moment, for every class variable, regardless of how trivial it is, I have created a function that sets it to a specified value. Most of the time, the code is as simple as variable = tempVariable; . However, I do this to make the code easier to modify in the long term if I want to add some sort of error checking, or if I want to create conditions under which the variables cannot be modified (e.g. after a sequence of events that use the value have been put into motion). In any situation where I need to modify these class variables, I use the setter function in order to maintain that modular, easy-to-modify nature. I do the same with getter return functions. Is this valid?

The second question has to do, generally, with program design and building up larger applications. By using multiple files, it’s possible to minimize the work the compiler needs to do from build to build, but the linker will always generally have just as much work. Is it possible to update or patch an existing executable without having to go through the entire linking process? How do regular commercial programs and video games do upgrade their own programs? Is it possible to generate two executables, each of which handles a different set of operations, and to slide control from one to the other as necessary, only rebuilding the executable that actually changes from update to update? If it is possible, is it ever done in practice?

Thanks.
Hello,

Having getters/setters or 'mutator' functions is a very common and practical practice for class design. Just keep in mind that if you're going to have those functions make the associated variable private - does no real good if they are public any way. Another practice you should get into the habit of doing is creating the deconstructor : ~ClassName() to delete any pointers you might have created in that class.

I've been working on a physics engine so I know kind of what it feels like to have a 'large' application. The thing is, you want your linker to take up time and to compile your code. All the linker is doing is taking each file and creating a set of binary for the computer to use. You could write your program in one main file and it will take the same amount of time. Having separate files and the ability to include them helps the programmer more.

As far as creating multiple executable files I'd say just create different 'builds' with different operations being active in each build. I mean... It's just plain convenient to have the code take ~30 seconds to link and compile and have an executable with all your delicious plans being executed.

btw, I'm not sure about your question in regards to moving control from one executable to another. It's just easier to recompile and execute. If you wanted that to be a function then maybe multi-threading?

If you have any more questions fire away!

Regards,
Anthony
Last edited on
You made the getters and setters private, ¿right?
My class variables are always private. Most of my setters and getters are public, except where the variables they correspond to are solely internal to the class and should not be accessed or viewed outside said class.

In reference to build times, I would imagine that the larger your project, the longer it would take to compile and link, regardless of how minute the changes to the code are. Right now, if I document out a single, trivial line in a function, at least that one source file gets recompiled and all the object files have to be relinked. It’s not a problem at the moment, but it is really inefficient, and I can see it being a much bigger problem with larger projects. Personally, I like to build and test executables, at least lightly, as frequently as I can. It reduces the risk of breaking something major or of having to identify, which of several large blocks of codes I just wrote is offending some other part of the code. Having to wait hours to test even a minor adjustment would make me far less likely to work this way, though.
Creating public getters and setters for all your variables, IMO, accomplishes nothing over having your variables public if you're calling these getters and setters from all over your code. All you've done is add the overhead of a procedure call to loading and storing variables.

The true art of encapsulation is understanding what operations are performed on an object and then making those operations public. Using the typical Player object in a game, you don't want to expose getters and setters for hit points for example. What you typically want to do is expose a function such as take_hit (int attack_strength). take_hit subtracts the attack_strength from the players strength and if <= 0 then invokes "player_died". This is far better than having some unrelated section of code deal with managing the player's health using generic getters and setters.

One technique for building up large applications is to isolate sections of you code into DLLs or library files. You might have one DLL for OS specific classes, another for graphics specific classes, etc. Once you have those DLLs built, they don't tend to change frequently, therefore you're not constantly compiling and relinking those classes thereby keeping the builds of your executable smaller and faster. If you design the DLLs correctly, you can reuse them across projects.





Getters and mutators often accompany badly designed classes. The class interface is the behavior, not a collection of independently accessible sub objects. What kind of, say, a car, has a meaningful behavior setX(int) or even moveTo(Point3d)? A car can turn the wheels and drive, but not teleport. Even stronger design point: anything you can "set" (say, make and model for the car) belongs to the constructor and nowhere else, unless your class really has the ability to create something out of thin air during its lifetime.

As for large applications, you can factor out code into shared libraries, so that changes to the library code do not require the relinking of the main executable. The trade offs are that link time optimization doesn't work across libraries and that the symbol resolution is postponed to launch time, and if you have a very large application, launch can take a long time, and if that is critical, this time is better spent during linking.
Last edited on
So, it’s better to not have mutators unless strictly necessary? Generally speaking, when I build the initial skeleton for my code, every variable gets its own getter and setter. For example, given a class variable, varX, I would also have the following:

1
2
3
4
5
6
7
8
9
10
11
int someClass::setVarX( int tempVarX )
{
  varX = tempVarX;

  return 0;
}

int someClass::getVarX( )
{
  return varX;
}


This is usually fine for most of the early work on a class’s functionality and lets me test things out assuming a perfect user. Later, however, when I start adding in something like error checking, I may or may not change the code to something more akin to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int someClass::setVarX( int tempVarX )
{
  if( isStarted())
  {
    if( tempVarX <= min )
    {
      if( tempVarX >= max )
      {
        varX = tempVar;
      }
      else
      {
        return 3;
      }
    }
    else
    {
      return 2;
    }
  }
  else
  {
    return 1;
  }

  return 0;
}


This way, I don’t have to individually find all the places where varX was manually set to some value, and manually add the above checks to each location. Is this grossly inefficient in the wider scope of things? It’s uncommon that I encounter problems like this, but as I coder, I prefer to assume that I’m not flawless and have my code and processes checked just as rigorously as I would check the user’s input.

Edit: Also, I keep the variables private because I don't want the variables to be set to anything outside the class without generally passing through the above error checking.
Last edited on
closed account (o3hC5Di1)
@Cubbi - Would you please be so kind as to elaborate your statement on accessors a little bit?
This subject has bugged me for a long time, after I first read this article:
http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

The main argument for using accessors seems to be "what if in the future you want to (count the amount of times member data was accessed, return the string in upper rather than lower case, change the datatype of the data member etc. etc.).

I have always found it hard to believe that at some point you would decide to change such things - to me that seems like bad initial design. However, I don't really have any experience on large scale projects as you do - which is why i would be very interested to hear your opinion. Also, this seems to be a rather controversial topic, so I was wondering if anyone has come across disagreements about this, for instance when starting a new job?

Edit: Some examples of how to replace accessors/mutators would be even more appreciated.

Thanks in advance.

All the best,
NwN

Last edited on
+1 @ Cubbi.

getters/setters are rarely necessary in real code. Or at least, they're not nearly as frequent as newbies tend to think they are. Classes are not just a collection of individual variables. Treating them as such is more than likely a sign that you are misusing them and/or have a bad design.

Look at existing classes in STL:

- vector
- string
- list
- fstream
- etc

How many getters and setters are there in those classes? There are very few. The closest thing they have to a get/set might be size/resize... but those clearly do more than getting/setting an individual variable.


codaraxis wrote:
when I build the initial skeleton for my code, every variable gets its own getter and setter.


You are clearly misusing classes if you are doing this, IMO.

The whole idea of encapsulation is that the class maintains its internal state privately, and only the interface for using the class is exposed publicly. If you are exposing every variable with a get/set function... then not only are you exposing the implementation, but you're also completely exposing its internal state.

If everything has a get/set, then there's really no point in having a class. You might as well just make everything public at that point.
Last edited on
From NwN (http://www.cplusplus.com/forum/beginner/77885/#msg419486):
The main argument for using accessors seems to be "what if in the future you want to (count the amount of times member data was accessed, return the string in upper rather than lower case, change the datatype of the data member etc. etc.).


That is/was precisely my thinking, except that I don’t consider it a part of poor design. For example, I frequently want to get a program running as quickly as possible to fulfill some need. I know that I would like to optimize and fool-proof the program down the line, but at the start, that’s not necessarily a priority. Once I have something in place and I know that the idea and basic design is viable, I can start tinkering with it. In a similar vein, I think it makes it easier to upgrade code. When I work on personal projects, I often have a list of priorities that sort of correlate to “versions”. To build the end product that I desire from start to finish would in some cases take years. I much prefer to build it to one level, use it, and then modify it down the line as needed. Is this really that inefficient? I’d make the functions inline, but the code calling the mutators doesn’t necessarily have permission to access the variables themselves.

I keep the variables private because I don’t want whoever is using the class and its members to tinker with said members without passing through the error checking I’ve set up. Furthermore, while not all the mutators are public, only the ones that the user would need access to in order to make use of the class. Some of the mutators are private and just for my own use. Those, I suppose, I could make inline functions.

Lastly, I don’t have classes that are solely collections of variables and mutators; since the variable need to be handled one way or another, though, I do find it convenient to already have mutators in place.

If my thinking is wrong, or if this is grossly inefficient, I’d very much like to know why. It’s why I created the thread in the first place. I’d also like a clear explanation of why it’s wrong rather than outright condemnation of the practice.
Last edited on
only the ones that the user would need access to in order to make use of the class.
The question remains, ¿why do need the user to access them?
By instance, std::string::c_str() is a getter. It's there for compatibility with the functions from C.

The problem with getters and setters is that you may put the logic in the wrong please.
Check out the link provided by NwN and http://pragprog.com/articles/tell-dont-ask
If my thinking is wrong, or if this is grossly inefficient, I’d very much like to know why. It’s why I created the thread in the first place. I’d also like a clear explanation of why it’s wrong rather than outright condemnation of the practice.


Encapsulation is the defining characteristic of OOP. If every member has a getter and setter, the class is not encapsulated. Without encapsulation, there is little reason to use classes.

Encapsulation is difficult to explain without falling back to examples. But the general idea is you want your class to represent a "thing". The class is in charge of maintaining its own internal state. The code using the class does not need to know (nor should it know) how the class works internally. It only needs to know how to use the class.


This allows for many long-term advantages. Some of the biggest are these:

1) It allows the implementation of the class to be greatly reworked/revamped at a later time. As long as the public interface of the class does not change, the implementation can undergo a complete overhaul... and no code outside the class will need to be updated.

If every member has a getter and setter - an overhaul / rework is much more difficult, because removing (or even renaming/repurposing) variables requires all code that gets/sets that variable to be adjusted.


2) When a bug is exposed in the behavior of a class, you know the bug is somewhere in that class. So you only need to go through 1 or maybe 2 source files to find and fix the bug.

When everything is publicly mutable with getters/setters, your member variables are effectively globally exposed, so bugs can be introduced by anywhere in the program. It makes it much harder to pinpoint exactly what code is causing the bug.


3) Hiding implementation details is necessary for polymorphism. If you expose implementation details, code that uses the class is relying on those details. If you want to swap that class out for a similar (sibling) class later, you might not be able to because the implementation details will likely be different.


For example, I frequently want to get a program running as quickly as possible to fulfill some need.


You sound like you are doing procedural programming. There's absolutely nothing wrong with that. I just assumed since you were talking about classes and private members in your original post that you were interested in OOP.

The problem with OOP is that it's not fast. Or at least... designing the classes is not fast. Effectively designing classes takes quite a bit more planning and foresight than your typical "code as you go" procedural program. The tradeoff is that properly designed classes are more stable, easier to use, easier to reuse, easier to expand, and easier to maintain.

So if you just want to quickly throw together something that does a small job -- you probably don't need (or want) OOP. OOP is strongest in larger projects where you're more interested in scalable, long-term functionality rather than getting a skeleton program out quickly.
closed account (o3hC5Di1)
Thanks a lot for that Disch - very informative as always.

All the best,
NwN
Thank you for the response. It was informative, cleared up some of my confusion, and helped flesh out the nature of encapsulation and OOP in my mind. I’d have posted this reply sooner, but I’ve been busy, and I wanted to make sure I had time to read the articles posted by NwN and ne555. Now having done so, I was hoping someone could check my conclusions. Depending on how valid they are, I have a few questions I’d like answered as well, but they can wait.

Check/Verify:
Object-oriented programming is the practice of using encapsulation to generate autonomous objects that have fixed, well-defined behaviours with an equally fixed and well-defined interface.

1. The purpose of the object should be completely known in advance and should not change after being set.

2. The object’s purpose should be kept as simple and as streamlined as possible, with said object being broken down into multiple smaller objects if it becomes too large and complex.

.....a. Inter-class dependencies should be minimized.

3. The interface the object makes publicly available should be static, regardless of alterations in the behind-the-scenes implementation.

4. The number of public object members should be kept to an absolute minimum.

5. Objects should limit the information it needs passed into it and that it passes back out.

.....a. The passing of objects should be preferred to the passing of simple data. (?)

As always, please add anything I've missed and rebuke any misunderstandings. Thanks.

Unrelated Question: Are there any additional, potentially hidden formatting codes by any chance? I've tried [list], [indent], and a bunch of other standard bbcodes, none of which have worked.
Last edited on
1. The purpose of the object should be completely known in advance and should not change after being set.


Ideally this is true. However in reality you need to be flexible. Often times it's impossible to predict all the needs of a project, so you'll have to be able to work in additional functionality.

Once a class is deployed, you likely will not want to remove any functionality from it (since doing so could break existing code that uses the class), however new functionality can usually be added to it pretty easily.

2. The object’s purpose should be kept as simple and as streamlined as possible, with said object being broken down into multiple smaller objects if it becomes too large and complex.


Yes. This is true of functions as well. There's a saying that if a function cannot fit on one screen of text, it is too large and should be broken up. While that isn't always possible/practical, the idea is good. A similar concept is true for classes.

You don't want a single class to do everything. A class should have a very specific purpose and should not reach outside that purpose.

.....a. Inter-class dependencies should be minimized.


One-way dependencies are fine, IMO. IE: having class A require class B is no problem. After all, the point of writing classes is so you can use them.

Where this gets problematic is when you have mutual dependencies (ie, class A requires class B and vice versa). This is sometimes necessary, and it isn't really bad by itself.... but it often leads to classes being intertwined and their purposes getting blurred together.

3. The interface the object makes publicly available should be static, regardless of alterations in the behind-the-scenes implementation.


This is similar to #1. The key thing to note is that you want to avoid changing/removing functionality after a class is deployed. Adding functionality is no big deal.

4. The number of public object members should be kept to an absolute minimum.


This is true.

Purists would even say you should never have any public object members. I don't necessarily agree with that 100% of the time though.

5. Objects should limit the information it needs passed into it and that it passes back out.


I'm not sure I agree with this.

A class/function needs what it needs. You can't really change the requirements of a task. Really you should just avoid giving it things it doesn't need.

.....a. The passing of objects should be preferred to the passing of simple data. (?)


Not entirely sure I understand what you mean here, but if you mean you should prefer passing objects around instead of ints and other basic types, then that's false.

There's nothing wrong with using basic types. Putting things in a class doesn't always make sense if they can be represented by a basic type. And there's nothing wrong with passing basic information around.

In fact, needlessly encasing basic information in classes will just obfuscate and complicate your code. Sometimes a struct with a dozen public members is much more preferable to a class with a dozen getters/setters.
Since this thread is still kicking, I owe NwN a response

NwN wrote:
The main argument for using accessors seems to be "what if in the future you want to...

Sure, that's the main argument for using them instead of public data members, which is what newcomers from C like to use (personally, 'want to perform error checking' sounds most convincing to me). But structure vs. behavior (or the similar divide highlighted by that earlier quoted link, 'ask vs. tell') is more fundamental:

If you choose to ask/expose structure, even if it is a virtualized (via a set of accessors) structure that doesn't correspond to the actual data members, the knowledge of what to do with the elements of that structure, which belongs to the class itself, is now spilled into the code that accesses it. Over time, there will be code doing arcane manipulations with the values obtained from the accessors, and worse yet, writing data back into the object via 'setters', with unexplained choices and far-reaching side effects, slightly different in different parts of a project.

Not to say there can't be value-semantic types that need to present a structure-like interface: C++'s oldest library, std::complex, has a pair of read/write accessors: real() and imag(), in addition to its public interface consisting of operators and math functions. Speaking of virtualized structures, it has another pair of accessors: abs() and arg(), although these are read-only.

NwN wrote:
I have always found it hard to believe that at some point you would decide to change such things - to me that seems like bad initial design.

Design really makes or breaks C++. In a large company, changing the specs or behavior of a component that was tested, released and is used by dozens, or maybe hundreds different developers is hard (but a good deprecation policy can push such changes through). If you're a vendor and it's your clients that are using it, it's even harder (and it's normal to maintain ancient branches of your software for 'special' customers. At one place we had a whole department for backporting select trunk fixes for the special customer's branch). But software life cycle is a whole other story, not specific to interface design.

NwN wrote:
I was wondering if anyone has come across disagreements about this, for instance when starting a new job?

There are always disagreements. I had to change my brace indentation style and variable naming conventions almost every time. My current place requires just enough accessors to make it possible to verify every user-servicable state of the object. I don't entirely agree with that -- there are other ways to write unit tests -- but observing trade-offs, pros, and cons of an architectural decision in a successful company is a learning experience, like at any job.
Last edited on
closed account (o3hC5Di1)
You don't owe me anything Mr. Cubbi, but I really do appreciate your taking the time for answering.

Thank you, and Mr. Disch too, very much for your elaborate answers.
Having input from experienced pro's like you is really invaluable.

All the best,
NwN
@Cubbi and Disch, you've both been an enormous help. While a lot of these are issues I’ve not yet encountered with my small projects, they make sense and help explain a lot of what is suggested. I was hoping I could call on you one last time to look at a sample class and just comment on its structure/design. Hopefully, I can then put the thread and topic to rest in my head and on the board.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class GeneralCase
{
public:
  GeneralCase (                    );
  GeneralCase ( int var1, int var2 ); //Uses setPubVar1() and setPubVar2()
  ~GeneralCase(                    );

  //Public Core Functions
  int startActivity( someObject &theObject                                   ); //Checks that pubVar1 and pubVar2 are properly set, then sets private vars as needed, then determines determineIsReady, then goes about doing its thing
  int startActivity( someObject &theObject, int tempPubVar1, int tempPubVar2 ); //Uses setPubVar1 and setPubVar2 then calls startActivity( theObject )
  int pauseActivity(                                                         );
  int stopActivity (                                                         );
  int reset        (                                                         );
  
  //Public Setters
  int setPubVar1( int tempPubVar1 ); //Will return an error code if getStartedStatus() is true
  int setPubVar2( int tempPubVar2 ); //Will return an error code if getStartedStatus() is true

  //Public Getters
  int  getPubVar1      ( );
  int  getPubVar2      ( );
  int  getStartedStatus( );

private:
  //Private Core Functions
  //More Functions Here That the Class Needs To Get Things Done

  //Private Generators
  int genPrivVar3( );
  int genPrivVar4( );
  int genPrivVar3and4( );

  //Private Setters
  int  setPrivVar1      ( int tempPrivVar1 );
  int  setPrivVar2      ( int tempPrivVar2 );
  int  setPrivVar3      ( int tempPrivVar3 );
  int  setPrivVar4      ( int tempPrivVar4 );
  int  setActivityStatus(                  );
  bool setStarted       ( bool tempStarted );

  //Private Getters
  int  getPrivVar1     ( );
  int  getPrivVar2     ( );
  int  getPrivVar3     ( );
  int  getPrivVar4     ( );
  bool determineIsReady( );
  
  //Variables
  
  //Externally Relevant Vraiables
  int pubVar1, pubVar2;

  //Internal Relevant Variables
  int privVar1, privVar2, privVar3, privVar4;
  int activityStatus;

  //Mixed Variables
  bool started;
};


This is how I normally lay out my classes. I use mutators internally because I feel it makes it easy for me to modify the implementation, and I use mutators as part of the public interface because it lets me control the incoming and outgoing data. From all the reasoning I’ve heard so far, none of it seems to apply to internal mutators.

As far as external mutators are concerned, if the “pubVar”s are likely going to change between uses of the class (i.e. they change every time after startActivity( theObject ) runs to completion), would it be better to get rid of their respective setters and getters all together and to just use startActivity( theObject, num1, num2 ) ? With some of my classes, there are a few variables that modify how they run, and I often find myself wanting to keep those same settings again and again. In that case, at least, I figure it’s easier for the class performing the action to hold on to the instructions than for the calling class to have to pass them in every time.

Lastly, I’ve seen a lot of cases on the board of people setting up D&D-type games. It’s very common for people to create a class with nothing, but public members corresponding to weapon properties, for example. From everything I’ve heard here, that seems like contraindicated by good design practices. I feel as if it would either be better to make them all structs. I know that if I were to do something similar, I’d prefer to keep the variables private and to create mutators that check all incoming data for validity. With a such a case, where your data structure is mostly a collection of values and their respective mutators, is it stylistically preferred to use structs instead of classes? Alternatively, should there be a POD struct with all the public variables in it and a corresponding class that can handle/generate/check said struct?
Last edited on
Topic archived. No new replies allowed.