开发者

When should and shouldn't you break away from OOP for speed/performance?

开发者 https://www.devze.com 2022-12-12 07:02 出处:网络
In their developer articles for Android, Google states that you should usually declare public variables rather than private ones with getters and setters to enhance performance on embedded devices (I

In their developer articles for Android, Google states that you should usually declare public variables rather than private ones with getters and setters to enhance performance on embedded devices (I suppose function calls are more expensive than just writing to an address).

I was wondering - to what extent should performance be sacrificed to stick to the OOP parad开发者_运维百科igm? And in what other cases does optimisation mean a break-away from 'good' coding practices?


Build it to be maintainable, and then hack it to be faster.

If you start with the hack - which you might not have needed - maintenance is usually a nightmare.


So long as performance isn't visibly affected, proper abstractions should be used.

Premature optimization is embarrassing.


I hate it when companies make statements like that, but don't provide statistics to quantify the issue.

That said: the tradeoff isn't really the OO paradigm. If you have both a get and a set, and that is an inherent part of your class design, making the variable public is perfectly valid from an OO point of view. If the performance increase is enough to matter, I'd expose the variable in those circumstances, but not otherwise.


In some sense I guess it depends on how important that performance is to your application and how much of a performance gain you really see by using coding practices that you may not think of as 'good'. But that being said, I always encourage developers to not cling to dogma and keep writing code the same old way because it was the way you were taught was "right". If you document the code well and use consistent and explainable coding practices, then I think it's perfectly fine to do something that may not fit into the "OOP paradigm". In the end, it's about working code that's maintainable.


In general, all forms of engineering are a matter of dealing with trade-offs. You need to compare the costs of one approach to the costs of another.

Sacrificing maintainability at the cost of anything else is always tricky, as it's easy to underestimate the future cost of unmaintainable code.

“The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet.” - Michael A. Jackson

That said, there is some argument to be made that the benefit of having accessors is actually pretty small. How many times have you ever had to replace a getter or a setter that just read/wrote-to a field with a method that actually did something? Given how rare this seems to be in practice, one could argue that using accessors for everything is "premature pessimization".


Most of the time, you are not supposed to optimize before speed matters, but this time you should.

The main issue here is not speed, but battery.

Now, Google indeed tell use to avoid getters and setters but only for an internal use, API should still expose only getters and setters. You should has well avoid object creation, better empty / clear one and reuse it if you can. And by all mean, avoid creating too many activities, view inflations are the most expensive process of all, with wireless connexion.

That said, you must be smart about it. You can't follow these advices all the time, your code would quickly become a mess, and we don't write Java to feel like coding in Fortran.

A good balance is to first create a clean / standard code that works nicely on the emulator. Then, when it works great, choose ressource intensives parts, most of the times loops, where you reduce this. But do it before shipping your app on the android market. To many apps kill android phones already, mine don't stand a day even starting the morning with a full battery.


What is involved in a function call? (I only took MIPS, so other architectures might be different).

  • Jump to the function
  • Save registers to the stack
  • Execute the function [body]
  • Copy the result to the return register(s) (if needed)
  • Restore the registers
  • Return to the caller

The jump/return might cause a CPU to need to reset the pipeline (I suspect this might not be an issue with modern CPUs though, typically it is predicting flow control). Saving/restoring the registers might not be necessary if the body is just a set or get. And if your inside a function you typically want to push/pull your return address to the stack before and after the function call respectively otherwise you will end up in an infinite loop.

Compare that with a save to or read from an address (which is typically one instruction vs a dozen+).


I find the coding guidelines by Google a tad misleading, if not questionable entirely.

They advertise against fundamental OOP paradigms such as programming against interfaces, not implementations, and also promote practices such as caching field lookups to save computing time.

I find them questionable not because I think they wouldn't have any effect, but I find them questionable because that's optimizing the 80% of your code where your application spends 20% of its time, rather than the other way around (those figures are obviously made up, but I guess everyone agrees that most Android applications don't spend the majority of their time in evaluating loop expressions).

Where an Android app really spends the vast majority of its time is view inflation and layouting. If you build even half-way complex user interfaces, and have ever profiled your app, you will realize that these are the things which really make your app come out slow at the end of the day. Compared to operations like view inflation, spending time on optimizing your loop variables seems almost ridiculous.

Funny enough, Google put their own guidelines ad absurdum by showing some numbers in an appendix:

Inflate 1 View from XML: 22,000

Call empty interface method: 15

Now run a profiler and see how much time your app spends in onLayout(), Adapter.getView() or inflate(). You may be surprised.


For the specific environment and applications they're talking about, that is good advice. I don't think it makes sense to generalize that to other situations, though. Android applications are by and large going to be small projects with little in the way of inter-dependencies. So, using public variables as the interface to some state is no big deal.

In particular, if you're choosing between trivial pass-through getter/setter methods and public variables, you're already most of the way down the "breaking encapsulation" road, so you might as well not pay the extra performance hit for no gain in flexibility. Given that it's Java, "build the world" is more-or-less the usual state of affairs when anything changes, anyway.

For a larger system, in a language like C++, you'd potentially have more benefit to a thin layter of abstraction like this.


Design should be sacrificed on the altar of performance when, and only when, testing reveals that the system will not otherwise meet its specifications.


I tend to stick to "good" coding practices, for me that means readability, whenever I can. Only on those very few occasions where performance is critical I deviate from that principle. And normally only when something has proven to suck performance-wise.

As for getters and setters; the advantage of using getters and setters is that you can log changes to parameters, and do some input validation. If that doesn't matter to you, and performance is indeed that critical, you could break abstractions. But I can't really believe that getters and setters can't be optimized away by using for example final classes.


In the case of Android, its important to take performance into consideration. If you do something like hold onto a large static reference, the Android framework may force quit your application when the user launches another activity or opens the keyboard (which reloads your view). It doesn't take a lot to hit this limit. This is really an issue of understanding the environment you are developing for.

In the case of non-mobile Java development, it makes sense to write easy to maintain code first, then optimize if needed.

Google does not say to avoid getters/setters and make your variables public for Android. They do advise to not use getters/setters from within a class to access its own fields. From http://developer.android.com/guide/practices/design/performance.html:

"Avoid Internal Getters/Setters

In native languages like C++ it's common practice to use getters (e.g. i = getCount()) instead of accessing the field directly (i = mCount). This is an excellent habit for C++, because the compiler can usually inline the access, and if you need to restrict or debug field access you can add the code at any time.

On Android, this is a bad idea. Virtual method calls are expensive, much more so than instance field lookups. It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly."


Millions of man hours have been wasted on those stupid little getters and setters. In most cases they are not needed. Start with public fields, and you can always change their usages to get/set methods later on if necessary.

0

精彩评论

暂无评论...
验证码 换一张
取 消