more info ⬇

@amattn

subscribe for more
stuff like this:

SW engineering, engineering management and the business of software



2014 02 04

Better Apps with Clang's Weverything or Wall is a Lie!

It sure would be nice if there was a code fairy flying over your shoulder that could sound a dulcet chime every time suspect code was introduced. Even better would be a swarm of fae to keep the entire project free of dubious practice. No such creatures seem to exist, but I will make the somewhat farcical claim that compiler warnings are a poor man’s army of code fairies and that enabling most all of them will eventually resolve into better apps. First, some backstory on how not to proceed.

-Wall is a lie!

The -Wall flag instructs the compiler to Enable All Warnings. However, gcc has an interesting definition of “All”, which is “Not All”. This is unfortunate as a codebase that compiles warning-free tends to behave better and have less uncovered edge cases.

The historical reason is that some warnings are intended to be more like notices where human judgement is required. The compiler is basically saying, “Watch out! Something questionable is happening here”.

Everyone’s definition of questionable is a bit different however, and there were some compiler warnings deemed as more informational than true exclamations of potential danger. Many of those warnings were excluded from -Wall, and as a compromise some of them were shoehorned into -Wpedantic and -Wextra.

After gcc usage became more and more widespread, it actually got harder to get new warnings included in the -Wall umbrella as this started to break toolchains. Once you get government standards bodies involved with the application of the -Wall flag, you more or less stop improving the -Wall flag.

Clang to the rescue

This brings us to Clang. Clang developers understand most of this history and decided that since -Wall and it’s ilk were mired in political and technical muck, they needed a new flag that is defined as “all current and future warnings forever”. They called it -Weverything which is pronounced “wevrything” and typically accompanied by large wavy outstretched arm gestures.

I’ll wait for that mental image to settle. Okay moving on.

But You Promised Better Apps!

This brings us to Better Apps.

Here’s a non-exhaustive, off-the-top-of-my-head list of edge cases and questionable behavior that -Wevertyhing can help diagnose:

  1. non-existent selector warning
  2. lossy integer conversion
  3. enum usage in switch statements
  4. memory leaks due to usage of self in blocks
  5. preprocessor and pragma issues
  6. slow builds due to not using modules

The list is roughly sorted in order of severity of potential problems. Stuff high on the list could cause runtime crashes and widespread decaffeination of coffee-stores around the world. Integer conversion edge cases in particular are a big source of crashes on 64bit iOS devices. Stuff towards the bottom simply wastes time & energy and likely induces hair loss.

-Weverything in Action

A small prototype project that I implemented in a few weeks that uses Core Data, some GCD, and some collection views and animations was my initial stab at -Weverything.

A clean build turned into a build with 307 warnings.

Many of these warnings are actually pretty nice and resolving them means my app is a little bit more resilient, a little bit more future-proof, and even builds a little faster.

Resolving them ended up only taking about 20 minutes or so, mostly thanks to Xcode under-appreciated Fix-It feature. The warnings spanned the range of important, nice, helpful, benign-but-I-just-want-the-warning-to-disappear stuff. At the end, I’m left with a handful of warnings I can’t or won’t fix.

At this point, we have to start disabling warnings. Because what -Weverything really means is “all current and future warnings forever, except those that I disable because of reasons”.

A Brief Interlude into Xcode

In Xcode, to enable -Weverything you need to go to the “Build Settings” pane. This can be done project-wide or only for specific targets. I tend to keep them strict for my app targets, then loosen them for test or tangential targets. The app gets a curfew, but the red-headed test targets can go out rutting like a drunken sailor for all I care.

The correct place to set -Weverything is in the “Other Warning Flags” line item.

If you wish to disable a certain warning, you first find out the warning flag’s root name then prepend -Wno- to it.

To get the warning flag’s root name in the issue navigator, right-click on a warning you’d like to disable, and select “Reveal in Log”. You should see something like this:

warning: enumeration values 'XXModeCount' not explicitly handled in switch [-Wswitch-enum]

The warning flag is in the square brackets at the end. Just swap out the -W with -Wno- to get the correct flag to disable the warning.

You can then add the disabling flag into “Other Warning Flags” and they should stop bugging you.

Just a note – if you have both target and project-wide settings, the target setting will override the project-wide setting. The “Resolved” column is handy to sort out the final settings.

Weverything But The Girl

Here’s what I ended up with:

-Weverything 
-Wno-objc-missing-property-synthesis 
-Wno-semicolon-before-method-body

The objc-missing-property-synthesis is a no-brainer one to disable. This is one of those informative warnings; the compiler is telling you that it is auto-synthesizing the property. We love that the compiler does this for us because manually synthesizing properties is not just boilerplate but also more tedious than doing Quality Testing on the Tickle Me Elmo assembly line.

The other one made me think quite a bit before disabling.

If you are going to disable warnings, make sure you have rational other than “I want the warnings to go away.” or “Stop breaking my beautiful build you bad compiler!”. Here’s an example of the thought process went through.

semicolon-before-method-body: I’ve long, long had the habit of adding semicolons after method name implementations

                        ⤹ HERE! 
- (void)doAction:(id)arg;
{
    //  
}

It makes copying and pasting between header and source files easier. It is optional in ObjC, but a syntax error in plain old C. I’ve found it on the whole to be a good little character, and greater than 99% of the methods I write have it. That being said, I don’t see it that much in the greater ObjC world and could be convinced to change my habits in the future.

For the vast majority of the Xcode-using population, I recommend starting with the following and then disabling warnings as necessary for your own project requirements and coding standards.

-Weverything
-Wno-objc-missing-property-synthesis

Temporarily Overriding Warnings With Our Friend #pragma

Sometimes you just want to disable warnings for a small section of code. This is done with the magic of #pragma. Specifically, the very nice diagnostic push & pop commands.

Here are some examples pulled from real code:

The direct ivar access warning:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
    if (_fetchedResultsController) // direct access to not trigger the lazy loader
        [self.collectionView reloadData];
#pragma clang diagnostic pop

The assign-enum warning when you just want to give it a 0:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wassign-enum"
// This is not a great example, but gets the point across
NSString *sig = [sigData base64EncodedStringWithOptions:0];
#pragma clang diagnostic pop

The “I’m so sorry, it’s really not my fault, but I really, really need that deprecated method” aka “Guilt-trip, stealing time from your future self” warning:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// Come on, you know better.  Stop using this:
[NSThing someDeprecatedMethod];
#pragma clang diagnostic pop

Finally, He’s Almost Done

Will your project still crash after enabling -Weverything? Probably.

Will it crash less? Probably.

If I had a moral of the story, it would probably be this variant of “trust but verify”:

Discipline is nice, but tool-assisted enforcement is even better.

In Summary:

Start with this in your app target’s Build Settings > Other Warning Flags:

-Weverything 
-Wno-objc-missing-property-synthesis 

And use this on a case-by-case basis and only when absolutely necessary:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-W<SOME_FLAG>"
// code...
#pragma clang diagnostic pop
2014 02 11

Thoughts on API Design

I’ve spent the better part of the last year designing and implementing APIs.

In that time, I’ve recently come across two very good articles:

Lastly, something I struggle with is making the API secure vs making it easy to use. You need a balance here. Oauth is so developer-hostile. I personally recommend a scheme similar to Amazon’s S3 service, as well as making everything run over https. One of the primary downsides of https (difficulty caching) doesn’t typically apply to API endpoints.

With respect to error codes, 4XX errors (the API consumer messed up), good error messages are important. Ideally, there should be enough information to help the consumer resolve the issue on their own. One security related message worth mentioning is that it is considered a better practice to combine username/password errors into one generic “Username and/or password is incorrect” type message rather than a separate message for username not found and incorrect passwords.

5XX (the server messed up) error messages should be vague as possible. Too much detail can actually expose you to attacks. I tend to use error numbers for traceability, but no error messages beyond the generic 500 Internal Server Error. If malicious parties are prodding at your API looking for vectors, you are better off treating them like mushrooms: in the dark.

2014 04 02

Useful Objective C Macros

A short treatise on snippits of indispensable utility.

Four broad categories of macros end up useful enough to find a home in the highly coveted precompiled header file.

  1. Convenience
  2. Logging
  3. Assertions/Sentinels
  4. Utility

For the sake of brevity, just the names of the macros are listed here, but you can find the full source at https://github.com/amattn/AMNGlobalUtilities/blob/master/GlobalUtilities.h

Convenience/Utility Macros

You should have your own set of useful macros that tend to follow you around. These are the one useful enough that I bring them along to new projects.

// Quickly make an NSError
#define AMN_QUICK_ERROR(error_code, error_description) 

// Quickly get portrait mode
#define AMN_ORIENTATION_IS_PORTRAIT 

// Profiling Macros
// Will log total time elapsed as from START_TIME to CHECK_TIME within a method.  The tag must be equal.
#define AMN_START_TIME(tag)
#define AMN_CHECK_TIME(tag)

Log Macros

Debugging is great. But sometimes you need log statements to get a better sense of flow through code. LOG_OBJECT and LOG_METHOD in particular get lots of usage.

These implementations not only log the value of the variable, but the name of the variable as well. LOG_OBJECT(self.id) prints out:

2013-05-08 11:52:45.615 ExampleApp[71311:c07] self.id 3716426951 SomeController.m:91

There exist variations that are far more flexible, but I prefer being explicit about type.

// standard types
#define LOG_BOOL(object)
#define LOG_CHAR(object)
#define LOG_INT32(object)
#define LOG_UINT32(object)
#define LOG_LONG(object)
#define LOG_ULONG(object)
#define LOG_INT64(object)
#define LOG_UINT64(object)
#define LOG_FLOAT(object)
#define LOG_DOUBLE(object)

// platform dependent
#define LOG_INTEGER(object)
#define LOG_UINTEGER(object)

// Various Cocoa/Objective-C log macros
#define LOG_OBJECT(object)
#define LOG_KIND_OF_CLASS(object)
#define LOG_METHOD
#define LOG_END_METHOD
#define LOG_METHOD_NAME
#define LOG_METHOD_THREAD
#define LOG_CLASS_METHOD

// Various Cocoa struct log macros
// NSRange
#define LOG_RANGE(range)
// CGPoint
#define LOG_POINT(point)
// CGSize
#define LOG_SIZE(size)
// CGRect
#define LOG_RECT(rect)
// CLLocationCoordinate2D
#define LOG_COORD2D(coord)

Assertion/Sentinel Macros

Assertion macros are very good for tightening up extremely rare edge cases. You shouldn’t be using assertion as general error handling in Cocoa. In fact, you shouldn’t be using try/catch at all in most Cocoa code; it is not idiomatic. However during development, macros such as ASSERT_IS_CLASS, SHOULD_NEVER_GET_HERE, and ASSERT_NOT_NIL represent a quick, readable way to explicit about intention and also noisily alert during testing.

This particular implementation first prints out an easy to spot header, then follows up with file, line number, object info and an indispensable stack trace.

If you’d like support in the debugger, “Show Breakpoint Navigator”, click the little plus in the bottom left of the window, and then “Add Exception Breakpoint…”. The default values will then cause the debugger to pause upon encountering any assertion.

// Standard Assertions
#define ASSERT_NIL(x)
#define ASSERT_NOT_NIL(x)
#define ASSERT_ALWAYS
#define ASSERT_TRUE(test)
#define ASSERT_FALSE(test)
#define ASSERT_WITH_MESSAGE(x)
#define ASSERT_TRUE_WITH_MESSAGE(test, msg)
#define ASSERT_FALSE_WITH_MESSAGE(test, msg)

// Useful, protective assertion macros
#define ASSERT_IS_CLASS(x, class)
#define SUBCLASSES_MUST_OVERRIDE
#define SHOULD_NEVER_GET_HERE

Utility

Lastly, just a couple of utility functions that are too useful to leave out. This is kind of a junk draw to be honest.

// Unabashedly cribbed from Wil Shipley (of Delicious Monster fame)
// http://www.wilshipley.com/blog/2005/10/pimp-my-code-interlude-free-code.html
static inline BOOL isEmpty(id thing)
// UUIDs are uuuseful.
static inline CFStringRef createUniqueString(void)

Again, you can find the full source at: https://github.com/amattn/AMNGlobalUtilities/blob/master/GlobalUtilities.h

2014 04 21

Notes on Chapter 1 of Authority by Nathan Barry

I was fortunate enough to receive a hard copy of Nathan Barry’s Authority. I’m going to try something new and post notes on the chapters as I read. If you want a quick recommendation, the answer is: Yes, you should buy this book.

Chapter 1: On Writing

An interesting side-note the author just threw in there:

Rather than having to continue high school for a set number of years, I was given a fixed amount of schoolwork I needed to complete to graduate. I saw that as a checklist and dove in.

If I recall correctly, he finished high school by 15 or 16 years of age.

Reading in between the lines, the author starts the book off talking about writing. Specifically, when to write (consistently) and what to write (write so that people learn). There is some incidental contact with the whys of writing, but later chapters delve more on the whys & hows of writing.

2014 04 23

Developer Catnip

At some point, nearly every new datastore, programming language or pre-launch platform has been placed on a pedestal of glory somewhere on the internet. These glory stools often show the tech enveloped with rays of sunshine and perfectly placed drops of morning dew highlighting the ideal surface. Every new tech needs promotion to flourish. Yet indiscriminate adoption of solutions that seem relevant to your pain points typically results in that feeling you get when you bite into a warm soft chocolate glazed donut with rocks inside of it. The short-sighted lusting of new hot tech ends up resembling some infernal combination of The Grass is Greener syndrome and blind faith pseudoscience.

It could also be reduced into a somewhat destructive form of optimism.

Your knowledge of your own toolset includes all the warts and melancholy involved with the realities of software development. The difficult-to-source internet quote: “comparing your behind-the-scenes with other’s highlight reels” comes to mind.

When we believe that a new tool will solve all our problems, we fall into the trap of optimistic information asymmetry. We read the blog post or listen to the 45-minute conference talk on how successful a person was in a specific situation, but rarely do we get an equally detailed and realistic discussion on the slope of their learning curve, the anti-patterns or the other myriad of pitfalls.

What does this mean? Should we never use new tech? Of course not. Otherwise, we would be using giant stone pillars for calendars and writing webapps via CGI scripts in perl.

Skepticism, not Cynicism

Optimism is critical to making progress in the face of incomplete information. However, it must be tempered with a healthy dose of skepticism. It is equally important to avoid the pitfalls of cynicism. The Skeptic’s mind can change in the face of evidence. The Cynic is just a narrow-minded pundit who thinks everything sucks.

Remember that unless you are hunting werewolves, there are no silver bullets.

Do your due diligence. Look for that evidence. Allocate time and manpower for research. Talk to experts or other people who have used the  catnip   new hot tool/language/environment before. In the age of Twitter, you can usually talk to the people who made the new hot thing.

As the evidence and your familiarity grows, start with small trials of isolated components. Don’t start a company and broadly proclaim that technology X will be the foundation of your new empire – unless you are competing with whatever I do. In that case, please do so. I also have more hot technologies you should know about.

Lastly, always factor in the risk/reward ratio for any new tech. Do the calculus on age, reputation and usefulness of the project. Use your best judgement. Measure the after-effects and don’t be afraid to change course.

Don’t skip the measure part. It is unequivocally the most important part of the feedback loop. Your job is not to use the hot tool - your job is do the best possible work you can.

The internet laughs at the world’s drug-addled cats, not with them. Don’t be a drug-addled cat developer.

2014 04 25

Notes on Chapter 2 of Authority by Nathan Barry

Continuing my experiment of publishing notes on what I read. Previously: Chapter 1.

Chapter 2: Basic Marketing

Before you spend months of your life creating something, you may want to test for some demand.

Content

You’d be surprised how little it takes to become perceived as an expert.

Why Email?

He also goes into detail with two case studies:

Summary

Teaching is Marketing. Test demand. The classic, recommended method is to use a Wordpress landing page on the internet. Write three epic blog posts. That is enough to begin building trust and expertise. Use email as a second-level filter for customer demand. Love email. Dispense with any preconceived notions you have about email. Email has a lot of mechanical and historical advantages.

Other posts in this series:



the fine print:
aboutarchive@amattn
© matt nunogawa 2010 - 2017
back ⬆