Regarding the PS3 / PS4 co-development issue, it's "simple": you code in a
modular and
functional manner.
Modularity allows a high-level (system-design) separation of each sub-portion of a large system via interfaces, so it's easier to make changes to the inner workings of each module without knock-on effects to other modules (as long as it doesn't affect the interface) - the other systems it interacts with are only concerned with the interface, not the nuts and bolts.
The functional paradigm removes "side effects", which are mainly unintended consequences of modifying shared data, because making changes to the way one area of code manipulates data without understanding how it affects the same data when fed to another area at another (or even "the same") time tends to breed particularly nasty bugs. Using a functional programming style can eliminate that side-effect (with some effort), further separating the inter-dependence of different parts of the overall system, allowing a robust environment for making future changes or providing several different options for a single module.
So the basic framework of the overall system is generic code that is easy to port, largely owing to its non-performance-critical nature. The specific implementation of something like a geometric transformation of a track element will vary from hardware to hardware, if only for the purposes of making it work as fast as possible.
That's where the modularity comes in: just swap out the implementation, when the time comes, by switching the code modules, all self-contained in a data-driven functional style to reduce side-effects. Once the modular framework is established and all interfaces are working, it implies you can work on all versions of a given module at the same time and get an idea ahead of time whether certain features are going to work on a given platform in a given implementation.
Of course, this is all in principle, because writing true modular and purely functional code is not easy, and requires some serious system-level design skills for all the module interfaces and efficient isolation of data-flow for the functional style. Not to mention the actual programming talent required to work in a functional style in a non-functional language like C++, in order to get most of the robustness of the functional style without too much of the usual slowdown ("inefficiency") of true functional languages.
The implication here is to design the overall system so that only the critical, swappable parts (i.e. those that are both performance critical and hardware dependent) are considered for a functional implementation, then you can save time everywhere else. A modular design goes a long way by itself, as long as the interfaces don't need to change much between versions.