Let me start by saying that all of my comments apply only to application level code. There is never an excuse any more to not follow standard encapsulation practice when writing library code.

This is one of those things where a little more effort up front pays off big later. Unfortunately, there are fairly strong incentives to not follow good practice, and you've tripped on one of the biggest.

At one level, code is often easier to read when you don't abstract away the representation. This is because you remove a level of indirection and bring the code one step closer to the hardware. Not having to wade through a sea of member functions to understand a module you are debugging is sometimes nice.

Plus, it's faster to write. Hiding the structure of an object forces a much different style of programming that--there is no way around it--takes longer than the equivalent functionality without the abstraction.

But, you pay for it later. Anything you write that is truly useful is going to provide functionality that you eventually want to either automate or embed in other applications.

If you've followed good OOPy1 procedure and hidden away the representation of your application, your user interface, and your state then it will be relatively easy to adapt your code to its new environment. You won't have to worry that today a FrobNazz is a string, but later needs to be a map<String, NetworkObject*>. You won't have to wonder which security critical function is going to try to read through a null pointer after the change.

On the other hand, if you've gone the easy way, you get to essentially rewrite the whole thing every time you need to bring it up on a new architecture, localize it to a new language (human language, not programming language), or embed it into another new system.

1- Referred to as gettin' oopy with your app