While getting rid of extraneous junk in an application package is easy using Trimmit, the only way to prevent "code bloat" (and accompanying excess RAM and CPU usage) is through good programming practices. Where most developers fall short is in poor optimization of borrowed code. Let’s take CTGradient as an example as it’s well known and used (or more accurately, abused) in dozens of applications.
CTGradient contains an incredible diversity of built-in gradients, gradient styles, and methods for creating fancy rainbows, radial gradients, linear gradients, aqua gradients, and a number of other interesting class and instance methods. It allows you to dynamically alter gradients by adding or removing colors, changing the level of transparency, filling NSRects or NSBezierPaths, rotating the gradient, etc. For demonstration purposes, all these features are excellent. For production, this is a nightmare.
CTGradient.m weighs in at over 1300 lines of code.
Ignoring Mr. Weider’s unique style of formatting, take a look through the code. If you’re putting this class in an application, you can immediately remove over a thousand lines. Just like that. But if you take some time to understand what’s going on, you can optimize this thing till it runs like a Ferrari.
You’ll notice Trimmit uses a gradient background for it’s window. Let’s cut down CTGradient until it matches the level of optimization of Trimmit’s gradient code.
Clear the junk
Firstly, let’s remove the methods we know for sure we won’t need. Remove the following methods completely from both the interface and the implementation (scroll down for more):
// We don't need the preset gradients
+ (id)dividerGradient;
+ (id)statusBarGradient;
+ (id)aquaSelectedGradient;
+ (id)aquaNormalGradient;
+ (id)aquaPressedGradient;
+ (id)unifiedSelectedGradient;
+ (id)unifiedNormalGradient;
+ (id)unifiedPressedGradient;
+ (id)unifiedDarkGradient;
+ (id)sourceListSelectedGradient;
+ (id)sourceListUnselectedGradient;
+ (id)rainbowGradient;
+ (id)hydrogenSpectrumGradient;
// We won't make any drastic modifications to the gradient once created
- (CTGradient *)gradientWithAlphaComponent:(float)alpha;
- (CTGradient *)addColorStop:(NSColor *)color atPosition:(float)position;
- (CTGradient *)removeColorStopAtIndex:(unsigned)index;
- (CTGradient *)removeColorStopAtPosition:(float)position;
- (CTGradientBlendingMode)blendingMode;
- (NSColor *)colorStopAtIndex:(unsigned)index;
- (NSColor *)colorAtPosition:(float)position;
// Now we don't need to conform to the NSCopying and NSCoding protocols
- (id)copyWithZone:(NSZone *)zone;
- (void)encodeWithCoder:(NSCoder *)coder;
- (id)initWithCoder:(NSCoder *)coder;
// We only need to fill a simple NSRect
- (void)drawSwatchInRect:(NSRect)rect;
- (void)radialFillRect:(NSRect)rect;
- (void)fillBezierPath:(NSBezierPath *)path angle:(float)angle;
- (void)radialFillBezierPath:(NSBezierPath *)path;
// Remove the entire (Private) category;
// but leave -addElement:
- (void)_commonInit;
// move setBlendingMode code into init
- (void)setBlendingMode:(CTGradientBlendingMode)mode;
- (CTGradientElement *)elementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtPosition:(float)position;
The following C functions are now unused:
static void chromaticEvaluation(void *info, const float *in, float *out);
static void inverseChromaticEvaluation(void *info, const float *in, float *out);
static void transformRGB_HSV(float *components);
static void transformHSV_RGB(float *components);
static void resolveHSV(float *color1, float *color2);
And also remove the following from the header:
typedef enum _CTBlendingMode
{
CTLinearBlendingMode,
CTChromaticBlendingMode,
CTInverseChromaticBlendingMode
} CTGradientBlendingMode;
Remove the <protocols> and unnecessary instance variables so the interface looks like this:
@interface CTGradient : NSObject {
CTGradientElement* elementList;
CGFunctionRef gradientFunction;
}
+ (id)gradientWithBeginningColor:(NSColor *)begin endingColor:(NSColor *)end;
- (void)fillRect:(NSRect)rect angle:(float)angle;
- (void)addElement:(CTGradientElement *)newElement;
@end
Before we go further, we’ll need to take a detour and fix the remaining code so that it compiles. That’s easy enough - just remove any references to code we’ve removed.
If you’ve been following along, your CTGradient should now look like this (also made it readable!).
In a few short minutes, we’re down from more than 1300 to a little over 200 lines.
It gets better.
Optimize it
First stop, fillRect:angle:. Since the gradient for Trimmit’s window only runs vertically (angle 90), we can straight away take out the angle argument, and also cut the entire if / else structure with the angle down to the two lines that are under the if(angle == 90). Ah, much better.
Now things start getting a teeny bit more complex - and fun.
The CTGradient code is written so that one can have many different color stops. The CTGradientElement struct has a nextElement which points to the next CTGradientElement and the position of the current element is stored under the float position. However, we need just two - the starting and ending shades.
Let’s take a look at cutting the multiple elements down to just two.
The addElement: method has a lot of looping to insert the element at the correct place. However, since we know that we only ever need two, we can cut it down to this:
- (void)addElement:(CTGradientElement *)newElement {
if(elementList) {
// elementList exists, add second element
elementList->nextElement = malloc(sizeof(CTGradientElement));
*(elementList->nextElement) = *newElement;
elementList->nextElement->nextElement = 0;
} else {
// no elements - add first element
elementList = malloc(sizeof(CTGradientElement));
*elementList = *newElement;
elementList->nextElement = 0;
}
}
Similarly with dealloc,
- (void)dealloc {
CGFunctionRelease(gradientFunction);
free(elementList->nextElement);
free(elementList);
[super dealloc];
}
While we’re at it, let’s clean up init as well:
- (id)init {
if(self = [super init]) {
CGFunctionCallbacks evaluationCallbackInfo = {0 , &linearEvaluation, 0};
static const float input_value_range[2] = { 0, 1 };
static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
gradientFunction = CGFunctionCreate(&elementList, 1, input_value_range, 4, output_value_ranges, &evaluationCallbackInfo);
}
return self;
}
Now we head to the linearEvaluation function. info passed in refers to elementList (see the CGFunctionCreate call). Again, since we know that we’ll only ever have two elements we can reduce it to:
void linearEvaluation (void *info, const float *in, float *out) {
float position = *in;
CTGradientElement *color1 = *(CTGradientElement **)info;
CTGradientElement *color2 = color1->nextElement;
out[0] = (color2->red - color1->red)*position + color1->red;
out[1] = (color2->green - color1->green)*position + color1->green;
out[2] = (color2->blue - color1->blue)*position + color1->blue;
out[3] = (color2->alpha - color1->alpha)*position + color1->alpha;
}
And now we can finally remove the lines from +gradientWithBeginningColor:endingColor: where the positions are set, and also remove the position float from the CTGradientElement struct.
We’re now down to a little over 100 lines. Your CTGradientElement.m should now be looking something like this. Going well, but let’s take things up a notch.
For Trimmit’s background, we’re not interested in the red, green, blue and alpha components - we just need a grayscale shading. This is the most fun part.
Instead of float red, green, blue, alpha; in the CTGradientElement struct, we can have just float shade;.
Now, during init we have:
CGFunctionCallbacks evaluationCallbackInfo = {0 , &linearEvaluation, 0};
static const float input_value_range[2] = { 0, 1 };
static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
gradientFunction = CGFunctionCreate(&elementList, 1, input_value_range, 4, output_value_ranges, &evaluationCallbackInfo);
The third argument, input_value_range is the domain. This gets passed into linearEvalution through *in.This is the independent variable. When we’re drawing the gradient, linearEvaluation is called with *in (the domain) starting at the first value of input_value_range and ending up at the second. So, something like 0.000, 0.001, 0.002 … 0.998, 0.999, 1.000. The function’s job is to set the the color components for each given value of the domain.
The first optimization we can make here is to return only one channel instead of four. This changes it to:
- (id)init {
if (self = [super init]) {
CGFunctionCallbacks evaluationCallbackInfo = {0, &linearEvaluation, 0};
static const float range[2] = {0, 1};
static const float domain[2] = {0, 1};
gradientFunction = CGFunctionCreate(&elementList, 1, domain, 1, range, &evaluationCallbackInfo);
}
return self;
}
This change impacts back on the linearEvaluation function - now it only needs to return one channel:
void linearEvaluation (void *info, const float *in, float *out) {
CTGradientElement *color1 = *(CTGradientElement **)info;
out[0] = (color1->nextElement->shade - color1->shade)*(*in) + color1->shade;
}
And don’t forget +gradientWithBeginningColor:endingColor:. We improve performance here, as we only need the shade - not a color. We can rename it to something appropriate.
+ (id)gradientWithBeginningShade:(float)begin endingShade:(float)end {
id newInstance = [[[self class] alloc] init];
CTGradientElement color1, color2;
color1.shade = begin; color2.shade = end;
[newInstance addElement:&color1];
[newInstance addElement:&color2];
return [newInstance autorelease];
}
Now we’re only returning one grayscale channel. But hold on, we’re still in the RGB colorspace! That’s easily fixed. In fillRect:, replace:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
#else
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
#endif
with:
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
CGColorSpaceCreateDeviceGray is device-dependent on Mac OS X 10.3 and below, but starting from Tiger, it’s now device-independent which is good in terms of appearance.
While we’re in fillRect:, we can also make a few more improvements:
- (void)fillRect:(NSRect)rect {
CGContextRef currentContext = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(currentContext);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
CGContextClipToRect(currentContext, *(CGRect *)&rect);
CGShadingRef myCGShading = CGShadingCreateAxial(colorspace, CGPointMake(0, 0), CGPointMake(0, NSMaxY(rect)), gradientFunction, 0, 0);
CGContextDrawShading(currentContext, myCGShading);
CGShadingRelease(myCGShading);
CGColorSpaceRelease(colorspace);
CGContextRestoreGState(currentContext);
}
I moved the startPoint and endPoint CGPoints straight into the CGShadingCreateAxial call. Also, we only ever fill the whole view with the gradient, so just put in 0 instead of using NSMinX and NSMinY. We could replace the CGPointMake(0, 0) with (CGPoint){0,0}, but I’m not sure if that’d be noticeably faster.
Our code is at a lean 80 lines. Now for the biggest change yet.
Heading back to dear old linearEvaluation. Look at this line:
out[0] = (color1->nextElement->shade - color1->shade)*(*in) + color1->shade;
What’s happening here? Think about it like this:
Essentially, we’re just "graphing" a straight line:
y = mx + c
where x is the position, *in, and y is the shade we return (out[0]), and c is the initial shade.
Since our x value only goes from 0 to 1 (see domain in CGFunctionCreate), at x = 0, we will have y = c. At x = 1, we’ll have y = m + c.

So we only need the start shade as our *info value, since we can have m as the difference between the final and initial shades. Let’s effect this in our code.
We can get rid of the CTGradientElement struct. Remove from the header:
typedef struct _CTGradientElement {
float shade;
struct _CTGradientElement *nextElement;
} CTGradientElement;
Instead of the struct, we’ll use a single shade instance variable. We don’t need the +gradientWithBeginningShade:endingShade: anymore, nor do we need -addElement:. So our interface now looks like this:
@interface CTGradient : NSObject {
float shade;
CGFunctionRef gradientFunction;
}
- (void)fillRect:(NSRect)rect;
@end
From the implementation, we can remove the free calls in dealloc as well as the whole of +gradientWithBeginningShade:endingShade: and addElement:. We can set the shade in the init method (and replace &elementList with &shade), and change the linearEvaluation function to:
void linearEvaluation (void *info, const float *in, float *out) {
out[0] = *(float*)info + (*in)*0.1;
}
The 0.1 is what determines how much brighter the top of the gradient is (it’s the m value of our straight line) compared to the bottom.
But since the (*in)*0.1 will go from 0 to 0.1 (as *in goes from 0 to 1), we can actually change the domain we declare for CGFunctionCreate to {0, 0.1} and have our function as:
void linearEvaluation (void *info, const float *in, float *out) {
out[0] = *(float*)info + *in;
}
You can now add accessors for shade if you need to change the shade of the gradient or you could even have an initWithShade: method. In fact, here’s an Xcode project with the gradient.
We now have our gradient code down from 1300 lines to just over 30 lines.
We’ve almost reached a similar level of optimization to Trimmit’s gradient. There will be further optimizations you can make, but it depends on what you’re using the gradient for. For example, if the gradient you’re drawing is always the same, you can optimize further by removing the shade instance variable and all references to it, and hardcode the value into the linearEvaluation function.
Getting to the end of this article, you’re probably thinking that it would be a bit of a waste to use CTGradient if by the time you optimize it for your application, it doesn’t resemble the original at all. And you’re quite right. The documentation already shows you how to draw gradients, yet the number of applications using CTGradient - the whole 1300 lines of it - is astonishing.
Please: When you use other people’s code, don’t put it in without a thought. Go through it, understand it, and optimize it for your specific need. For the better performance and reduced RAM usage, computers will thank you.
124 Comments so far
Leave a commentPages: « 1 [2] 3 4 » Show All
Whoa! Once in a blue? This thing usually gets called at every single ‘display’.
You could go so far as to call it a good thing, but it doesn’t justify waste. CTGradient is a demo of the gradient drawing. The whole thing shouldn’t be mindlessly plonked into any and every app. It’s not as if it’s hard to write your own gradient code. Just copy and paste from the docs!
One principle of Wil Shipley’s that I do try to follow - tiny code.
mentioned by Ankur on November 21, 2007 5:09 pm | Permalink
I’ve downloaded and ran the optGrad project you’ve linked above, and i’m not seeing results anywhere near what you’ve been describing.
http://myskitch.com/funkeemonk/activity_monitor-20071121-150847/
And here’s the memory usage at full-screen on my machine: http://myskitch.com/funkeemonk/activity_monitor-20071121-152425/
Only about 0.1MB difference between the two.
published by Joe Goh on November 21, 2007 5:12 pm | Permalink
“at every single ‘display’”: True, but that is probably not very often, except when resizing windows. And if it is, then yes, optimizing it like this is justified. But not until it actually becomes a problem.
“But it doesn’t justify waste”: A thousand lines of demo code in a library routine can’t be more than a kilobyte added to the final binary. I’d hardly call that ‘waste’.
“tiny code”: In your app, absolutely. In a library written by someone else? As long as it works and does a good job, I don’t really see a good reason to cut into it.
posted by Joachim Bengtsson on November 21, 2007 5:15 pm | Permalink
It’s not a ‘library’. That’s the point. The whole thing is a demo.
recorded by Ankur on November 21, 2007 5:22 pm | Permalink
“Probably” is not very certain. An NSLog where you draw the gradient will found out pretty quickly.
I think the best thing people can do here is to actually read the CTGradient.m code before making comments.
I’m not going to argue whether this five minute is optimization “worth it” or not. I know it is. If you read the code you’ll also know it is. (Or better yet, if you read the documentation, you’ll realize that you don’t even need the class to draw simple gradients.)
I really didn’t expect so much discussion over something so small. An application is a guest on the user’s system. It should behave as such.
stated by Ankur on November 21, 2007 5:33 pm | Permalink
Ankur, you seem to be repeatedly confusing peoples’ sentiment that your optimizations are not worth the time, with a sentiment nobody is expressing: that they’re not valuable. Mixed up in all of this is a defensive tone among respondents, probably inspired by the righteousness and dismissiveness with which you express your argument.
You keep reflecting back to and obsessing on “if you read the docs,” etc. Well, you’ve got the luxury of time and you chose to focus on gradients. You know a lot about them, and you’ve got some mathematical cleverness that allows you to sit down and, as you say it, spend “5 minutes” optimizing this situation.
Most of us would not have had this cranked out in 5 minutes. Obviously it was a lot easier for us to just link in the trusted class and have it do its thing. This is how most of us get work done. We’re not in the business of fine-tooth-combing through every single action our application makes. If we were, we’d be too busy optimizing our own array and dictionary collection classes to ship an app.
You’ve obviously got real talent but in the realm of optimization you’re expressing more ignorance than brilliance, as you repeatedly argue for measurement methodologies that make no real impact on the end user experience.
posted by Daniel Jalkut on November 21, 2007 11:16 pm | Permalink
‘We’re not in the business of fine-tooth-combing’
Yes and your reputation in that regard precedes you.
announced by Rick on November 21, 2007 11:35 pm | Permalink
‘You’ve obviously got real talent but in the realm of optimization you’re expressing more ignorance than brilliance, as you repeatedly argue for measurement methodologies that make no real impact on the end user experience.’
Wins today’s award for the most pompous pile of bile quoted on the World Wide Web. As anyone can see the ‘righteousness and dismissiveness’* of which you so high handedly speak is your own and no one else’s.
*According to dictionary.com ‘dismissiveness’ is not a word.
expressed by Rick on November 21, 2007 11:41 pm | Permalink
‘Premature optimization is the root of all evil.’ - TONY Hoare
Yes Tony Hoare is well known. But it’s not exactly premature anymore when the bloody application is finished, is it? Some people really need to get a clue, read the quotes from the giants whose shoulders they’ll never be permitted to stand on, and try to understand what those giants mean and do not mean. Who knows? Fantastic things might result. Such as halfway decent code for the first time ever.
revealed by Rick on November 22, 2007 12:02 am | Permalink
‘You’ve obviously got real talent but in the realm of optimization you’re expressing more ignorance than brilliance, as you repeatedly argue for measurement methodologies that make no real impact on the end user experience.’
Hilarious! Go on, tell me ‘memory is cheap’ I dare you ;o) As I see it, as the old saying goes, “look after the pennies and the pounds will look after themselves”. All optimisation is worth it, period. Whether it saves memory or space on disk or merely sharpens one’s mind it is worth it. For sure it takes time but there’s a very instructive inverse proportion there - the less one does it the longer it takes to do, whilst if one makes it part of one’s daily approach to coding the methods become second nature.
published by diem on November 22, 2007 12:48 am | Permalink
@ Red Sweater
“Well, you’ve got the luxury of time and you chose to focus on gradients”
Ok? So you don’t like doing your homework?
spoken by Sean on November 22, 2007 1:51 am | Permalink
Sean - I don’t have time to do “my homework” on everything. Do you?
Who’s going to vet and optimize darwin for us? I’m sure we could save a few bytes!
recorded by Daniel Jalkut on November 22, 2007 1:53 am | Permalink
Actually, its “the love of premature optimization” that is the root of all evil…except for all that other evil whose root is the love of money.
It should be noted that all of the “bloat” you removed for CTGradient did strip out functionality. The price of using code that does more than you need is…extra code. You can’t really call that “bloat”.
If all you want to do is draw a gradient with one color and two endpoints, you don’t need to use CTGradient at all, as you have pointed out. One can copy and paste code from Apple docs.
Have you really optimized anything here? You’ve stripped down CTGradient until it effectively implements a simple gradient. We’re not even talking about CTGradient any more.
For your next blog posting, how about hacking the bloat out of OmniNetworking so that it only offers UDP connections? That would be fab.
composed by Captain Obvious on November 22, 2007 2:14 am | Permalink
Whoa. I think the entire article and many of the commenters missed the point of CTGradient. It’s most likely all things to all people who simply need a gradient. I’ve written gradient routines and optimized them. It wasn’t fun. But every time I needed a different gradient, I had to rewrite the routine and re-optimize. Suddenly, I have dozens of gradient drawing routines, each slightly different. Not cool.
My solutions was to move everything into a custom class and abstract everything away. My optimizations lost to convenience. I regained some sanity and I’d do it again. Then I found CTGradient and started using it. Instead of having to make changes to my own gradient class, CTGradient just seemed to do what I wanted when I wanted something different. I like that and consider it a worthwhile trade off.
If you only have one type of gradient or need speed, then you should obviously roll your own. The docs give you all the code you need for a simple gradient. However, if you need something more complex and don’t want to take the time to roll your own, CTGradient is great.
Also, until I see a reproducible table of results for an example application, I have to call “premature optimization.”
posted by Grayson on November 22, 2007 2:31 am | Permalink
Joe Goh - I do not believe the Joel on Software quote applies in this situation. I read that same article some time ago. Joel was talking about throwing code away without taking the time to understand it, and then rewriting it from scratch. Taking the time to understand the code and then iteratively refactoring it and/or throwing away the parts that are not needed is not “throwing away all that knowledge”.
Daniel - I would not argue the merits of this based on performance, though there may be a performance-based argument. I believe that reducing 1300 lines of code to 30 is a savings in itself, especially if you ever have to modify or debug your reused code. The benefit to the end user in this case is reduced shipping time for that update with the new feature or bug fix.
In my opinion, less code is always better than more code, but I may be influenced by my job in safety-critical software, where each untested statement is viewed as a potential bug, and we are required to write tests that achieve 100% MC/DC coverage of the code.
declared by Tim on November 22, 2007 3:27 am | Permalink
@ Daniel
“I don’t have time to do “my homework” on everything. Do you?”
If I decide to stick my neck out and make snide comments, I’d make an attempt to make sure I know what I’m talking about. But then again, you’re just a blogger who suffers from unwarranted self-importance, so I wouldn’t expect anything more out of you.
“Who’s going to vet and optimize darwin for us? I’m sure we could save a few bytes!”
Oh, so open source projects like Linux were created by just one guy plugging away at a keyboard for years and years, with no improvements (however small they may be) done by anyone else. Uh huh.
Do us a favor, think of this as being a thanksgiving dinner. The adults are busy discussing things at the dinner table. Take your slice of turkey, and go back to the childr- Oops, I mean, “indy” developer table.
Anyway, I’m still stunned as to how someone would be COMPLAINING about having code being reduced to about 15% of its’ original line count.
All your original comments go back to you just being TOO LAZY to read ANY SORT OF DOCUMENTATION and then somehow think that THIS IS THE WAY YOU’RE SUPPOSED TO DO THINGS!
professed by Sean on November 22, 2007 4:42 am | Permalink
Well at least something good came out of this utterly idiotic comment thread. I learnt my preferred C indent style has a name. Whitesmiths FTW.
mentioned by Jonathan Wight on November 22, 2007 5:05 am | Permalink
I should clarify my above statement:
I’m stunned that people are complaining about having code being reduced to about 10% of what it originally was, before AK even started to do any real heavy lifting.
posted by Sean on November 22, 2007 5:08 am | Permalink
@Sean: When you’re a one man shop developing, testing, shipping, marketing and supporting several applications then optimising some 3rd party code you are using to do gradients, that you decided to use for the sole reason that you can just drop it in and use it just isn’t worth the time. Now that someone else who had the time has done it then people might start using the new code. Unfortunately time is limited and so you have to prioritise if you want to get anything done.
reported by Martin Pilkington on November 22, 2007 5:16 am | Permalink
Rick -
C.A.R. Hoare is correct as well. Same dude.
spoken by Ian Baird on November 22, 2007 6:04 am | Permalink
Observation and accuracy may be considered basic skills required of a programmer. The following simple test may help highlight issues relating to file quality where small and simple is regarded best. There is no time limit to the test that follows where the task is to read and manually count the occurrence of the character f within the following sentence…
‘Finished files are the formal result of years of scientific formulation of research.’
Take a few minutes rest and then repeat the exercise. Compare the recount with the previous result. Ask a colleague to perform the same. The worth of the exercise may well rely on repeating the exercise a number of times whilst being observant, analytical and recognising potential sources of error.
Those not capable of arriving at a consistently satisfactory stable count may of course drop this text into an appropriate file editor and perform a search but then the real purpose will be lost. The results of the test may just provide an insight into why file bloat is related to quality, stability and security.
What did you notice as the exercise was repeated?
Where are sources of error on such a trivial task?
Are there any lessons to be learned from the observations?
If there are issues encountered in a small task such as this what are the implications for anything more complex?
uttered by Tony on November 22, 2007 6:06 am | Permalink
Bravo! Like a beautiful piece of music Ankur. Well thought out, written and expressed. I’m a manufacturing engineer and can appreciate a finely crafted process. Clean engineering is a thing to behold and speaks volumes for the intellect that creates it.
And yes, it does have a positive effect on the world it operates in. It’s something wonderful.
SLmanDR
uttered by Steve on November 22, 2007 6:19 am | Permalink
@sean
no one is complaining about the reduction in line count. people just want to see some numbers about any improvements in speed, binary size, and memory usage. it’s well known that programmers aren’t good at picking where to optimize without the use of a profiler.
reported by Taybin on November 22, 2007 6:25 am | Permalink
Looks like a follow up from Rick:
http://www.rixstep.com/2/1/20071121,00.shtml
I don’t think I’d be understating it to say, this guy is a 911 conspiracy theory-level fucking nutter.
determined by Jonathan Wight on November 22, 2007 6:29 am | Permalink
Is it so difficult to get Ankur’s point?
Does everybody agree that lean, bloatfree code is
-easier to read and to understand
–therefore easier to maintain
–therefore easier to keep free of hidden bugs
-wasting less disk space
-performing better
?
OK.
The big question is: why did Ankur have to waste his time optimizing CTGradient? Why didn’t the original author do in the first place what Ankur had to now? That code didn’t just come into existence on its own, it was created by somebody, and this person should have felt responsible for producing quality code.
Take Ankur’s Trimmit tool. You can de-bloat all sorts of applications in a breeze. Still, why should you have to waste valuable time doing that, when you already paid the software author for this job? Because this should be an important part of the software authors job! Hallo!?
Imagine you check into a hotel and in the room they give you, you find out that YOU have to clean the on-suite bathroom and change the last person’s dirty bedcloth? I bet you would be off to the manager in no time.
Bloated code is no different than a dirty toilet in a hotel room.
uttered by g.org on November 22, 2007 6:46 am | Permalink
“Bloated code is no different than a dirty toilet in a hotel room.”
reasonded by Jonathan Wight on November 22, 2007 7:05 am | Permalink
“The big question is: why did Ankur have to waste his time optimizing CTGradient? Why didn’t the original author do in the first place what Ankur had to now?”
It seems to be that a lot of Ankur’s “optimisations” are really specialisations. The code suddenly isn’t particularly useful to everyone any more. It isn’t really fair (and is in fact rather idiotic) to compare the two codebases any more.
Accusing anyone of using Chad’s original code of not caring about code bloat is frankly a little presumptuous if not downright rude. The line count (which may or may not equal bloat) has gone down, but so has the general usefulness of the code.
spoken by Jonathan Wight on November 22, 2007 7:37 am | Permalink
Whitesmith! Coming from Pascal, my C style was kind of formless until I learned the value of consistency from McConnell’s Code Complete, from which I took the Whitesmith brace indentation style.
McConnell didn’t so much recommend it as stress its advantages, and I agreed. My immediate superior and I disagree on it quite often, but that’s the purpose of code formatters. Use ’em, heretics.
recorded by Allan on November 22, 2007 7:45 am | Permalink
As Ankur said, there’s nothing wrong with Chad’s original code for demonstration purposes. Frankly, if someone puts the whole thing in an app instead of the one from the docs which is way smaller, then there’s every reason to accuse them of bloat. Intentional or not is another matter.
(Correct me if I’m wrong, but) I think that’s the point. Code should be specialized to fit the implementation, unless it’s a shared framework or library.
divulged by Harley on November 22, 2007 7:46 am | Permalink
Precisely. If I have a gradient in Trimmit, it should be for Trimmit. Code that’s useful for everyone is fine for everyone. For a single app, it should be for that single app only.
declared by Ankur on November 22, 2007 7:51 am | Permalink
You know, I just realized I’ve been using SQLite all this time but I probably only use half the features. Time to start choppin’ code! And I bet there’s loads of system frameworks I don’t need..
Seriously, though, couldn’t you have just said, “I found out that CTGradient does a lot of stuff I don’t need, so I copied out the 30 lines of code I was using from it.” And if you still need to pretend you’re educating the masses: “If you’re using CTGradient, you should consider whether you’d be better off using the CGShading functions instead.”
Now THERE’S a useful reduction in bloat.
stated by Dave on November 22, 2007 8:11 am | Permalink
Read the article next time?
stated by Harley on November 22, 2007 8:14 am | Permalink
“Precisely. If I have a gradient in Trimmit, it should be for Trimmit. Code that’s useful for everyone is fine for everyone. For a single app, it should be for that single app only.”
Oh Ankur!
You don’t really understand the term “code re-use” at all. Chad’s code is useful for everyone - as is. If developers consistently re-wrote 3rd party code there would be very few apps actually shipping.
Instead of telling people to re-write their 3rd party code you should be telling them to profile their code, identify any bottlenecks and start optimising there.
proclaimed by Jonathan Wight on November 22, 2007 8:24 am | Permalink
This discussion is getting off the topic. It appears people are not reading the article before expressing their opinions, hence the high level of lame and irrelevant comments.
published by Ankur on November 22, 2007 8:30 am | Permalink
Pages: « 1 [2] 3 4 » Show All
Leave a comment