Thursday, December 26, 2013

Switching contact from SMS to iMessage

So my girlfriend finally got an iMessage capable phone, but Messages on my phone still insisted on sending SMSes. Even after starting to receive iMessages in the same conversation. Even after a message sent from the Messages app on OS X was duly noted as being an iMessage!

Various attempts to fix this state of affairs had no effect: changing the contact number to iPhone, deleting the conversation(s), twiddling with Messsages settings on both phones, including the "Send as SMS" preference.

What did work was performing a reset of the Network Settings.

Tuesday, October 15, 2013

Should you use CoreData?

The answer, of course, is "it depends".

Now that we have that out of the way, I want to have a look at Drew Crawford's You should use Core Data, which manages to come up with a less nuanced answer in its 2943 words. It's an older article (2012), but recently came to my attention via Drew McCormack (@drewmccormack): "Great post", he wrote, and after reading the article I not just disagreed, but found that Twitter wasn't really adequate for writing up all the things wrong with that article.

Where to start? Maybe at the beginning, right in the first paragraph the following is called out as a "myth":

Among them, Core Data is designed for something–not really sure what–but whatever it is, it’s a lot more complicated than what I need to do in my project.
First here is a categorical mistake, because unless Drew knows the exact requirements and engineering trade-offs in every iOS application, he can't know whether this is true or false, fact or myth.

The second mistake is that the basic statement "CoreData was designed for something else" is actually true. CoreData's design dates back to NeXT's Enterprise Object Framework or EOF for short, and EOF was designed as an ORM for talking to corporate relational database servers, with a variety of alternate back-ends for non-relational DBs (including the way cool 3270 adapter!).

Obviously the implementation is different and the design has diverged by now, but that is the basic design, and yes, that does do something that is more complicated than what some (many?) developers need.

Details.

Next sentence, next problem:

I just want to save some entities to disk.
I may well be reading too much into this, but using the word entities already bakes so many assumptions into the problem statement. When I actually do want to save entities, databases in general and CoreData in particular are somewhat higher on my list of technologies, but quite often I don't start with ERM, and therefore just have objects, XML or other data. While these could be ER-modeled with varying degrees of difficulty/success, they certainly don't have to be, and it's often not the best choice.

In the enterprise system described in REST: Advanced Research Topics and Practical Applications, we removed the database from the rewrite, because the variety of the data meant converting the DB into a key-value store one way or another, or having a schema that's about an A0 page in small print (a standards body had developed such a schema and I think we even got a poster). We instead ended up converging on an EventPoster architecture that kept the original XML feed files around and parsed them into objects as necessary. No ERM here.

The next couple of paragraphs go off on an ad-hominem straw man tangent making WAG assumptions about the provenance of iOS developers and more WAGs about why that (assumed) provenance causes said developers to have these misconceptions. Those "misconceptions" that actually turn out to be true. Although largely irrelevant, it does contain some actual misinformation. For example the fact that categories don't get linked with static libraries is not an LLMV bug, it's a consequence of the combined semantics of static libraries and Objective-C categories irrespective of compiler/linker versions.

Details.

Joel

Then there's another tangent to Joel Spolsky's article on Things You Should Never Do (the link in Drew's article is dead), such as rewriting legacy code from scratch, which Joel describes categorically as "single worst strategic mistake" that any software company can make. In the words of the great Hans Bethe: "Ach, that isn't in wrong!":

  1. Just because Joel wrote something makes it right or applicable why?
  2. While Joel makes some good points and is right to counter a tendency to not want to deal with existing code, his claim is most certainly wrong in its absoluteness, both empirically (the system referenced above was a rewrite with tremendous benefits, then there's OS X vs. trying to keep fixing Classic Mac OS indefinitely etc.) and logically: it only holds true if all your accumulated complexity is of the essential kind, and none if of the accidental kind. That idea seems ludicrous to me, virtually all software is rushed, has shifting requirements that are only understood after the fact, has historical limitations (such as having to run in 128KB of RAM on a 7MHz CPU with no MMU) etc.

    Sometimes a rewrite is warranted, though you should obviously be wary and not undertake such a project lightly.

  3. Of course the biggest non-sequitur in the whole tangent is "How on earth does the problem of reading source code and rewriting legacy systems apply to this situation?". Apart from "not at all"? We don't have access to CoreData source code and there is no question about us rewriting it. Well, actually, I used to have such access, but even though my remit would have allowed some rewrites, I don't think I could have done a better job for the technology constraints chosen. The question is whether to use it or not, including whether the technology constraints are appropriate.
  4. And no, not every persistence solution ends up as effectively a rewrite of CoreData.

Details

After that ill-conceived tangent, the article goes right back to the next unsubstantiated ad-hominem:
Here are some things you probably haven’t thought about when architecting your so-called data stack:
Apart from the attitude somewhat unbefitting to someone who gets so much wrong, well, Nein, but lets's look at some of these in detail:
  • Handling future changes to the data schema: this just isn't hard if you're not using a relational database. In fact high variability of the schema was one of the reasons for ditching the DB in you know...
  • Bi-directional synchronization with servers...hah hah...!
  • Bi-directional synchronization with peers...see above
  • Undo support: gosh, I wish there were some sort of facility that would manage undo support on my model objects, if I had my way, Apple would add this and call it NSUndoManager. Without such a useful class, I'll just have to do complicated things like renaming old versions of my data file or storing deltas.
  • Multithreading. Really? Multithreading?? If you think CoreData makes multithreading easier rather than harder, I have both a nice bridge and some oceanfront property in Nevada to sell you.
  • Device/time constraints: the performance ca(na)rd. CoreData is slow and memory intensive. It makes up for this by adding the ability and the requirement for the developer to continuously tune the working set, if that is an option. If continuously minimizing/tuning the working set is not an option (i.e. you have some large datasets), you're hosed.

Details

Magic

Then we're back to the familiar ad-hominems/straw-men and non-sequitur analogies for a couple of paragraphs, nothing to see there. The whole analogy to Cocoa is useless: yes, Cocoa is good. How does this make CoreData good (it may or may not be, there simply is no connection) or appropriate for my tasks? Also, Cocoa in particular and Apple code in general is not "magic". I've been there, I've seen it and I fixed some of it. A lot of it is good, some excellent, but some not so much (sleep(5) anyone?).

The section entitled But, there are times not to use CoreData, right? could have been the saving grace, but alas the author blows it again. Having a "mark all as read" option in a NewsReader application is a "strange" "corner case"? Right. Let me turn this section around: there is a very narrow range of application areas where CoreData is or might be appropriate. Mostly read-only data, highly regular (table-like) structure, no need for bulk operations ever, preferably no trees either and no binary data. Fairly loose performance requirements.

What Apple says

The section on "what Apple says" is also gold, though I have to give credit to the Apple doc writers for managing to strongly suggest things without actually explicitly claiming them, strongly enough to fool this particular writer:
Apple’s high-level APIs can be much faster than ‘optimized’ code at lower levels.
This is obviously true, but completely meaningless. My tricycle can be faster than a Ferrari, for example if the Ferrari is out of gas or has a flat tire, or just parked. When we actually measured the performance of applications adopting CoreData at Apple we invariably got a significant performance regression. Then a lot of effort would be expended by all the teams involved in order to fix the regression, optimization effort that hadn't been expended on the original application, usually making up some of the shortfall.

I find the code reduction claim also specious, at least when stated as an unquestionable fact like this. In my experience, code size was reduced when removing CoreData and its predecessor EOF. Had we had exactly the requirements that CoreData/EOF were designed for (talking to existing relational enterprise databases), the result would almost certainly been different, but those were not our requirements, and I doubt that most iOS apps have those requirements (and in fact, CoreData didn't even support taking to external SQL databases, at all, a puzzling development for all the EOF veterans).

For managing small amounts of data inside in iOS application, CoreData is almost always overkill, because it effectively simulates an entire client/server enterprise application stack within your phone or desktop. The performance and complexity costs to pay for that overkill are substantial.

So Should You Use Core Data?

As I wrote: it depends.

The article in question at least adds no useful information to answering that question, only inappropriate analogies, repeated claims without any supporting evidence and lots of ad-hominems that are probably meant to be witty. If you believe its last section, the only reason developers don't use CoreData is because they are naive, lazy or ignorant.

This is evidently not true and ignores even the most basic concepts that one would apply to answering the question, such as, say, fitness for purpose. CoreData may well be the best implementation of an in-process-ORM simulating a client-server enterprise app there is, and there is good evidence that this is in fact true (certainly the people on it are top notch and some of the code is amazing). However, all that doesn't help if that's not what you need.

Considering the gleefully paraded ignorance of not just alternatives but various other programming aspects, I'd take the unconditional advice this article gives with a pinch of salt. Mountain-sized pinch, that is.

Tuesday, July 2, 2013

News from the Blogocalypse

So Google shut down Reader. When it happened all my news feeds went dead. I looked through the settings in my news reader, NetNewsWire 3.3.2, found the checkbox for "sync with Google Reader". Unchecked it.

It started syncing again, I did a "mark all as read" and things were back to normal. Now about that Snowden fellow...

Monday, July 1, 2013

What language Y is to LISP as Mac OS X is to Unix?

In his Rarely Asked Questions, Paul Graham once more espouses LISP as the ultimate, untoppable programming language (and yes, autocomplete wants to approriately turn that into "unstoppable").

One of the points he makes to support this, is that for any language to become as good as LISP, it would actually need to become LISP. While it is a cogent point and well argued, I don't buy it. More precisely, this is what he writes on what it would take to add the equivalent of LISP macros to another language:

But it would be hard to do that without creating a notation for parse trees; and once you do, your language has become a skin on Lisp, in much the same way that in OS X, the Mac OS became a skin on Unix.
Hmmm...I am not sure that this analogy is making his point, because Mac OS X is far, far superior to raw Unix for most people, and preferred by hackers, as he himself writes in Return of the Mac:
All the best hackers I know are gradually switching to Macs.
Of course, I may be stretching the analogy too far, but it seems to me that it doesn't support Paul's thesis of LISP superiority, but rather clearly points to some language Y that delivers LISP's power in a much more useful and usable form.

Any ideas what this language Y might be?

Sunday, June 30, 2013

Inbox management for RSS and Mail

Marco Arment notes that those complaining of RSS Inbox overload are not using RSS correctly: it should be used to check on a possibly large number of rarely updated but valuable sites.

He recommends simply deleting feeds that are updated frequently. I have a slightly different approach: two basic feed directories. One is my A-List, which contains feeds that roughly fall into the "rarely updated but valuable" category, and the other is my River of News, which are feeds that I enjoy and which keep me up-to-date, but which I don't mind clearing out by marking all as read.

Incidentally, pretty much the same goes for my E-Mail Inbox: as much of the lower priority stuff as possible is sorted into specific mailboxes automatically. The rest I triage quickly into one of 3 categories: action, read-ponder, will-file.

I used to sort by categories and that didn't work at all. In fact, it frequently managed to invert the actual priorities, leaving me focused on e-mails that weren't actually important, just hard to categorize, whereas most of the important e-mails would have their own categories and disappear from view.

Saturday, June 8, 2013

NSBezierPath description...

...shows the path segments as Postscript commands. So the following code:
  id p= [NSBezierPath bezierPathWithRect: NSMakeRect(10,20,200,100)];
  NSLog(@"p: %@",[p description]);
yields this output:
  Bounds: {{10, 20}, {200, 100}}
  Control point bounds: {{10, 20}, {200, 100}}
    10.000000 20.000000 moveto
    210.000000 20.000000 lineto
    210.000000 120.000000 lineto
    10.000000 120.000000 lineto
    closepath
    10.000000 20.000000 moveto
Neat!

Monday, May 27, 2013

Root View Controller and Autorotation

Must have the former or the latter won't work.

For some reason my Mussel Wind application was running fine without a root view controller, but with the annoying "Applications are expected to have a root view controller at the end of application launch" message. I vaguely remember autorotation being somewhat tricky, but in the end it was working and all was good.

Until I got the request to add zoom to the large version of the web cam view (you get it when you tap the image). Put in the scroll view, set it to zoomable, added the tap gesture recognizer. All good. Except nor more autorotation. Put in all the debugging messages for rotation masks, and shouldRotate etc. All called, but only on creation, not when the device is rotated. Nada.

On a whim, decided to fix the missing root view controller message by adding the view controller manually. First, no joy because UIKit was sending a "viewControllers" message that wasn't being handled. This despite the fact that my class is a straight UIViewController subclass and rootViewController is documented as taking just that. Oh well, just implement that as returning an empty NSArray and presto: autorotation!

Monday, January 21, 2013

More Objective-C Drawing Context Pleasantries

It's been a little over half a year since I first made my pleasant Objective-C drawing contextpublic, and I haven't been idle. In the process of retrofitting my own code to use MPWDrawingContext and adding more and more graphics (for example, I now do my icons in code), I've discovered a lot about making drawing with code a more pleasant experience.

Blocks

Blocks seem to be a really wonderful match for a graphics context, and most of the changes involve blocks in some way.

Bracketing operations such as gsave/grestore now have block versions, so the Objective-C block structure reflects the nesting:

    [context ingsave:^(Drawable c ){
        [c translate:@[ @130 ,@140]];
        [c setFont:[context fontWithName:@"ArialMT" size:345]];
        [c setTextPosition:NSMakePoint(0, 0)];
        [c show:@"\u2766"];
    }];
This is somewhat more compact than the plain code, which for correctness should also have a @try/@finally block wrapped around the basic drawing so exceptions don't mess up the graphics state stack.
    [context gsave];
    [context translate:@[ @130 ,@140]];
    [context setFont:[context fontWithName:@"ArialMT" size:345]];
    [context setTextPosition:NSMakePoint(0, 0)];
    [context show:@"\u2766"];
    [context grestore];
Similar for drawing shadows:
    [context withShadowOffset:NSMakeSize(0, -8 * scale) blur:12 * scale  color:[context  colorGray:0 alpha: 0.75] draw:^(Drawable c ){
        [[[c setFillColorGray:0.9 alpha:1.0] ellipseInRect:ellipseRect] fill];
    }];
Again, this seems a little clearer than having to explicitly set and unset, makes it harder to miss the end of the bracket when moving code around and remains exception-safe.
    [context sethadowOffset:NSMakeSize(0, -8 * scale) blur:12 * scale  color:[context  colorGray:0 alpha: 0.75]];
    [[[context setFillColorGray:0.9 alpha:1.0] ellipseInRect:ellipseRect] fill];
    [context clearShadow];

Stored, delayed and repeated drawing

You can create an object for later drawing by sending the -laterWithSize:(NSSize)size content:(DrawingBlock)commands message. For example, here is a simple diamond shape:
    NSSize diamondSize=NSMakeSize(16,16);
        id diamond = [context laterWithSize:diamondSize
                              content:^(id  context){
            id red = [context colorRed:1.0 green:0.0 blue:0.0 alpha:1.0];
            [context setFillColor:red];
            [[context moveto:diamondSize.width/2 :2] 
				lineto:diamondSize.width-2 :diamondSize.height/2];
            [[context lineto:diamondSize.width/2 :diamondSize.height-2]
				lineto:2 :diamondSize.height/2];
            [[context closepath] fill];
        }];
We can now draw this anywhere we want, and at any scale or orientation, using the -drawImage: message.
    [context drawImage:diamond];
You also have layerWitSize:content: and bitmapWithSize:content: messages if you want to specifically use CGLayer or CGImage instead, but using laterWithSize:content: preserves maximum quality, and it will automatically switch to a CGLayer when rendering to a PDF context in order to minimize PDF file size.

Patterns

I talked about patterns earlier. What I didn't mention then was that this is just the ability to use a stored set of drawing commands (see previous section) as a color:
    [context setColor:diamond];
I am not going to post the comparison to plain CG here, you can read it in the original Apple documentation.

I should note that this currently works for colored patterns, not for uncolored patterns, due to the fact that I haven't yet exposed color spaces. The basic process will be very similar.

Polymorphic object arguments

Path construction and graphics state messages with point arguments are now available in a version that takes a single object argument, in addition to the format with anonymous float arguments (moveto:(float)x :(float)y).
  • moveto:
  • lineto:
  • translate:
  • scale:
The single argument can be an Objective-C array:
    [context moveto:@[ @10, @20]];
Alternatively, any custom object that responds to count and either objectAtIndex:, (float)realAtIndex: or getReals:(float*)buffer length:(int)maxLen can be used. The scale: message can also take a single NSNumber and will treat that as uniform x and y scale.

Linecap parameters

Linecap parameters can now be set using distinct message:
  • setlinecapRound
  • setlinecapButt
  • setlinecapSquare
Having multiple messages rather than a single message with a parameter probably seems odd, but it actually reduces the number of names involved, and these names are nicely scoped to this context. The constant strings or enums that are typically used have global scope and therefore tend to need ugly and hard-to-remember prefixes:
    [context setlinecapRound];
vs.
    [context setLinecap: kCGContextLinecapRound];

Future

Another reason to be as purely message-based as possible is that it makes bridging to other languages easier, for example for interactive drawing environments: Creating a badge (youtube).

I've also started experimenting with other outputs, for example creating a version of the same badge composed of CALayer objects using the same drawing commands. Other output should follow, for example web with SVG or HTML 5 Canvas or direct OpenGL textures.

I also want to finally add image processing operations both stand-alone and as chained drawing contexts, as well as getting more complex text layout options in there.

p.s.: now on hacker news

(The People) 45874 : 1 (Carmen Ortiz)

As of right now, the White House Petition to remove Carmen Ortiz has garnered 45874 signature in the 9 days since January 12th. The one asking to recognize her 'outstanding' contributions, active for 5 days now received a slightly smaller number: 1. Maybe I should graph this?

Monday, January 7, 2013

Dependency Injection is a Virtue

DHH recently made a claim of Dependency Injection not being entirely virtuous, and got support from Tim Bray. While both make good points, they are both wrong.

Having hard-coded class-names like in the example Time.now is effectively the same as communicating via global variables. DHH's suggestion of stubbing out the Time class's now is selling us mutable global variables as the solution to global variables. Or more precisely: passing an argument to a method by modifying a global variable that the method reads out and restoring the state of the global variable afterward.

If that's "better", I don't really want to see "worse", and not wanting that sort of thing has nothing to do with being a Java drone limited by the language. And my experience with time-dependent systems tells me that you really want to pass the time into such a system generally, not just for unit testing.

Of course, having n-levels of AbstractFactoryFactory indirection could actually be argued as being worse, as Tim convincingly does, but that's one implementation of DI that's hobbled by Java's limitations. For a DI solution that's actually simple and elegant, check out Newspeak's  module system (PDF): there is no global namespace, modules are parametrized and all names dynamically resolved.

If you want synthetic time for a module, just instantiate that module with your own Time class.

Sunday, January 6, 2013

Objective-C is TIOBE Language of the Year Second Time in a Row

The TIOBE Index shows Objective-C as "Language of the year 2012". As it also won the honor in 2011, this now makes it only the 2nd language to win the award twice (Python won 2007 and barely edged out Objective-C in 2010), and the only one to win it twice in a row.

Although this surge in popularity is certainly largely due to the popularity of the iOS ecosystem (iPhone, iPad, AppStore), the fact that it continues despite Apple loosening its policies and alternatives popping up suggests that there may be more going on: maybe developers are discovering that Objective-C is a pretty fun and productive language, warts and all?

It'll be interesting to see wether Objective-C has now peaked, as Tiobe predicts, or wether it manages to expand back into other areas that could benefit from its qualities.

As last year, table and graphic reproduced here because Tiobe doesn't appear to keep an archive:

Position

Jan 2013

Position

Jan 2012

Delta in Position

Programming Language

Ratings

Jan 2013

Delta 

Jan 2012

Status

1

2

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

C

17.855%

+0.89%

  A

2

1

http://www.tiobe.com/content/paperinfo/tpci/images/Down.gif

Java

17.417%

-0.05%

  A

3

5

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Objective-C

10.283%

+3.37%

  A

4

4

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

C++

9.140%

+1.09%

  A

5

3

http://www.tiobe.com/content/paperinfo/tpci/images/Down.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Down.gif

C#

6.196%

-2.57%

  A

6

6

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

PHP

5.546%

-0.16%

  A

7

7

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

(Visual) Basic

4.749%

+0.23%

  A

8

8

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

Python

4.173%

+0.96%

  A

9

9

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

Perl

2.264%

-0.50%

  A

10

10

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

JavaScript

1.976%

-0.34%

  A

11

12

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Ruby

1.775%

+0.34%

  A

12

24

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Visual Basic .NET

1.043%

+0.56%

  A

13

13

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

Lisp

0.953%

-0.16%

  A

14

14

http://www.tiobe.com/content/paperinfo/tpci/images/Same.gif

Pascal

0.932%

+0.14%

  A

15

11

http://www.tiobe.com/content/paperinfo/tpci/images/Down.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Down.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Down.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Down.gif

Delphi/Object Pascal

0.919%

-0.65%

  A

16

17

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Ada

0.651%

+0.02%

  B

17

23

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

MATLAB

0.641%

+0.13%

  B

18

20

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Lua

0.633%

+0.07%

  B

19

21

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Assembly

0.629%

+0.08%

  B

20

72

http://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gifhttp://www.tiobe.com/content/paperinfo/tpci/images/Up.gif

Bash

0.613%

+0.49%

  B

Tpci trends 2013