tag:blogger.com,1999:blog-48617302488085533322024-03-12T22:54:46.221-07:00Heath TechHeathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-4861730248808553332.post-68303252342740445332016-11-25T22:19:00.003-08:002016-11-25T22:19:30.349-08:00Response to Apple: The Good, the Bad, and the UglyThis started life as a comment on <a href="http://steve-yegge.blogspot.com/2016/11/the-monkey-and-apple.html">Steve Yegge's The Monkey and the Apple post</a>.<br />
<br />
In the section Apple: The Good, the Bad, and the Ugly, Steve said:<br />
<blockquote class="tr_bq">
[Objective-C] has generics, literal syntax for sets/dictionaries/arrays, try/catch/finally macros, extremely well-implemented lambdas with proper closure capturing (unlike nearly every other non-functional language out there), properties, and many other modern conveniences.</blockquote>
<h4>
[Objective-C] Has Generics</h4>
Objective-C's generics are extremely weak. You can only define a generic type with a class method, so you can't have per-method types like in Java. Also, Objective-C classes aren't generic, so generic type-safe casting isn't possible.<br />
<h4>
Literal Syntax For Sets/Dictionaries/Arrays</h4>
Literal sets/dictionaries/arrays aren't generic, so you must use old-fashioned mutable collections if you want generic safety.<br />
<h4>
try/catch/finally macros</h4>
You're never supposed to use exceptions for control flow. Exceptions are only for programmer error, and are almost always supposed to cause a crash. Thus, the @try/@catch/@finally macros are useless.<br />
<h4>
Extremely Well-Implemented Lambdas with Proper Closure Capturing</h4>
Objective-C lambdas (blocks) are the one bright spot of the language, excepting that <a href="http://www.openradar.me/radar?id=4960057443745792">they don't work properly with generics</a>.<br />
<h4>
Missing Features</h4>
Steve left out nullability from the language feature list. It works somewhat, but I haven't had enough time yet to do a proper analysis. The nullability syntax is overly complex, however. <a href="https://twitter.com/heathborders/status/801121980879667200">There are 3 different ways to declare nullability.</a><br />
<h4>
Downsides of Swift</h4>
<div>
Later, Steve says:</div>
<blockquote class="tr_bq">
Obviously today I'd do it in Swift</blockquote>
<div>
This seems obvious, but Swift has a few major downsides that could be deal-breakers.</div>
<div>
<ul>
<li><a href="https://twitter.com/Javi/status/799710627715371009">Some people report inability to print variables from LLDB for the past 2 years</a>. </li>
<li>Swift only supports modularity with dynamic libraries. If you use too many dynamic libraries,<a href="http://useyourloaf.com/blog/slow-app-startup-times/"> your app will start slowly</a>. Objective-C still supports static linking, so you can use as many libraries as you want without affecting startup time.</li>
<li>The Swift runtime adds 18 MB to your app's binary size. Apple will probably strip unneeded binaries from the runtime when individual users install, but if 32-bit ARM and 64-bit ARM both have the same-sized binary, the Swift runtime adds 9MB at install-time.</li>
</ul>
</div>
Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-65625305735436082632016-01-18T15:21:00.001-08:002016-01-18T15:21:28.791-08:00Mobile Testing Brain Dump<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">A friend asked me for advice on testing, and I thought my response might be helpful for the rest of the world. This is simply a brain dump, with very basic structure, and there might be some minor inaccuracies. I encourage corrections, and will update the post with them as needed. :)</span><br />
<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;"><br /></span>
<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">Each platform has it's own testing hell. First unit testing:</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">For Android, unit testing is a real pain. By default, Google recommends that you run your unit tests on an emulator or real device, even if they don't require any UI components. This is because there are no Android libraries that run directly on the development box. Thus, you're best bet is to segment your Java code into as much pure Java as possible and write pure-Java unit tests for that. Then, write Android-specific unit tests for the code that uses Android libraries. You can write those with JUnit, and they'll run on an emulator or device. If this isn't an option, you can look into <a href="http://robolectric.org/">Robolectric</a>, which is an attempt to create a fake Android environment that runs on the JVM. I recommend against Robolectric because it doesn't have the exact same behavior as a real device, and doesn't support the latest Android (or it didn't back in 2014 anyway).</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">For iOS unit testing, you basically must use XCTest. There are other frameworks like Kiwi or Specta, but they're just BDD frameworks that wrap XCTest by artificially creating test objects based on their own method and assertion specification patterns. I recommend using plain XCTest because Apple hasn't had great support in the past for running unit tests. Thus, if you stray far from Apple's recommended path, you're likely to find that stuff doesn't work between releases of Xcode. On my last project, we used ordinary XCTest and things worked fine. You can easily add <a href="https://github.com/hamcrest/OCHamcrest">OCHamcrest</a>, which <a href="https://twitter.com/qcoding">Jon Reid</a> maintains (he's a great guy and very helpful if you have questions). OCHamcrest is just a better way of performing assertions, but it doesn't actually alter the testing structure, so I think it'll still remain pretty compatible with each new version of Xcode. If you need to mock, I recommend <a href="http://ocmock.org/">OCMock</a>.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">For UI interaction testing:</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">For Android UI interaction testing, you can use essentially 2 different options: Espresso and UIAutomator. You use espresso if you want to run tests exclusively within your own app. You use UIAutomator if you want to run tests that might call out to many different apps (for example, if you have a twitter client, you might write a UIAutomator app that opens the Photo Gallery, presses the Share button, and shares a photo to your twitter client). With espresso, you have access to objects within your application because the tests run within your application's process. With UIAutomator, the tests run outside your application's process, so you must use only the UI itself to perform actions and verify results. UIAutomator uses Android's accessibility framework to navigate the DOM and extract values from UI controls.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">For iOS UI interaction testing, things are unfortunately a bit complicated. Up until iOS8, Apple recommended the UIAutomation tool in Instruments. UIAutomation seems like it works for simple tasks, but it starts breaking down by not recognizing views on the screen or not properly tapping the right things. Worse, you must write UIAutomation tests with javascript. Also, UIAutomation doesn't support interacting with other apps or with system alerts, so you can't grant permission for your app to use the GPS, Photos, etc, or interact with other apps. Finally, there is no simple support for running UIAutomation tests from the command line, and there is no actual unit testing framework for it, though primitives exist that you can use to build your own.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">Because of these problems with UIAutomation, Square created <a href="https://github.com/kif-framework/KIF">KIF</a>. It runs your tests within XCTest (which itself just runs within an instance of your app). It relies on some non-public API for interacting with the UI. It worked well up to iOS8, but I've never run it against iOS9, so I don't know if it works there. It doesn't support interacting with system alerts or with other apps because your tests are confined to your process.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">Starting with iOS9, Apple created XCUIAutomation, which allows you to write UIAutomation-style tests within an XCTest-like context. I've never used it, so I don't know how well it works, but I've talked to people at Apple who said that despite XCUIAutomation's similar name and APIs, a new team worked on it and completely rewrote it, so maybe it works better. I don't know if it will support interacting with iOS system alerts or other apps, but I doubt it.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">In short, if you want to run on iOS7, iOS8, and iOS9, KIF might be your best option. If you want the best official support, XCUIAutomation might be your best option.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">Finally, if you're doing UI interaction testing, you should try to run all your tests on as many different OS/Hardware combinations as possible. <a href="https://aws.amazon.com/device-farm/">Amazon</a> and <a href="https://developers.google.com/cloud-test-lab/?hl=en">Google</a> have options for this, but Google's is in private beta, and only supports Android. Thus, I recommend trying Amazon's. I haven't used it yet, but since I'm an Amazon employee (by way of Twitch), I plan to give it a try as soon as I get some time to work on UI Interaction testing.</span><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><br style="color: #222222; font-family: arial, sans-serif; font-size: small;" /><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: x-small;">However, even though all these tools for UI interaction testing exist, I recommend not relying too heavily on it. I've tried on many occasions with many different systems to do UI interaction testing (including on Swing, Eclipse, and Selenium), and I've found that UI interaction testing always tends to be brittle, regardless of the framework or GUI toolkit. Generally, front-ends change a lot, and when they change, they tend to break all the underlying tests. You can mitigate that a bit by writing an abstraction over your UI to perform basic tasks (sort of like <a href="https://cucumber.io/">Cucumber</a> encourages you to do with Rails apps), but also adds to the cost of testing. You can theoretically get a lot of benefit from UI interaction testing, but I've never seen it work well on a really fine-grained level. </span><br />
<br />Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-21036083067001962612015-04-17T22:31:00.003-07:002015-04-18T07:10:41.538-07:00The 0.1x Programmer is not a Myth<h2>
TLDR</h2>
People that claim 10x programmers are a myth haven't spend enough time with terrible programmers.<br />
<h2>
Intro</h2>
Thanks to <a href="https://twitter.com/kmoir">@kmoir</a>, today I watched <a href="https://twitter.com/jacobian">@jacobian</a>'s very interesting PyCon 2015 Keynote:<br />
<blockquote class="twitter-tweet" lang="en">
Holy crap, the <a href="https://twitter.com/pycon">@pycon</a> A/V team got my keynote online *already*! Check it out: <a href="https://t.co/LHc0YgKrg1">https://t.co/LHc0YgKrg1</a><br />
— jacobian (@jacobian) <a href="https://twitter.com/jacobian/status/587318216034136064">April 12, 2015</a></blockquote>
Jacob asserts that because most people fall onto a normal distribution that most programmers must as well. He makes a great analogy between marathon running ability and programming ability.<br />
<br />
He illustrates his point with this chart:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVIHBRezKefM1ZH8EM2T9H4UbDHleC3MwamhD1M9QKtwvtsNkGu33tljaYBzI90MOiXhRmc838FCzO3EanyWJM2LXMd8rWcexX1RNYS6IjPZFONfsi9gw35pDfjBwa261ZyqQ5wgm7KhQd/s1600/normal-distribution.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVIHBRezKefM1ZH8EM2T9H4UbDHleC3MwamhD1M9QKtwvtsNkGu33tljaYBzI90MOiXhRmc838FCzO3EanyWJM2LXMd8rWcexX1RNYS6IjPZFONfsi9gw35pDfjBwa261ZyqQ5wgm7KhQd/s1600/normal-distribution.png" height="199" width="320" /></a></div>
<span id="goog_1437824944"></span><span id="goog_1437824945"></span><br />
<h2>
Groundwork</h2>
I wholeheartedly agree that the mythical perception negatively affects a beginners confidence and that it is hurting our industry pipeline. I completely disagree that programmers lie on a normal distribution. Like Jacob, I have no data to support my claims, however, I'll be honest and say so, rather than presenting my claims as fact.<br />
<br />
First, I want to introduce the three pillars I think someone needs to be a successful programmer (these probably make you successful at most things): hard work, a desire to improve, and intelligence. I posit that these qualities are mutable, but generally it is better to find someone that already has high values of at least two of these qualities. For example, if you're trying to hire a programmer for an esoteric language without much of a community, you might look for someone with intelligence and a desire to improve. If you need someone to pore over thousands of lines of COBOL looking for two-digit dates, you might optimize your hiring for hard-workers; they might not need to know the deep inner workings of the systems they're modifying. They might just need to expand all the records that contain a date.<br />
<br />
There exist a lot of hard-working, intelligent programmers. There are unfortunately not as many with a desire to improve. A friend once told me you can have X years of experience, or 1 year of experience X times. (I'm sure that quote is attributable to someone famous.) I think this is extremely common in programming.<br />
<br />
I believe that programmers have programming ability on a distribution more like this (enjoy my professional illustration):<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7ih3Fx9OGeV27jSvcMjMpw58nnp9FciTTibwruIsxJuCDGc7-a1WEppuYl0PVg7_2vwTJmKaVEfJi8XqDJAqXUdRdc1KGiUPOapZtlGAi3D7ktphYWZBbUvBl1o7wMFnU0PAPfr5hEqLJ/s1600/anecdotal-distribution.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7ih3Fx9OGeV27jSvcMjMpw58nnp9FciTTibwruIsxJuCDGc7-a1WEppuYl0PVg7_2vwTJmKaVEfJi8XqDJAqXUdRdc1KGiUPOapZtlGAi3D7ktphYWZBbUvBl1o7wMFnU0PAPfr5hEqLJ/s1600/anecdotal-distribution.png" height="240" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
However, I also believe that programmers have job-acquisition ability on a normal distribution:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggvpzuJ32tvE7EW1_FsL0FxUv8NZSh-XUNkVIV9Z2J8GiQYTL7uI1puqpFjlEgNmZqIOHINHKo6y1yXwXM8lsjsMH0ssEqYmf7iMeYMsj35iQJI-6Y5G_44L98TX6SK5rcZx_RfC9JdSox/s1600/interviewing-distribution.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggvpzuJ32tvE7EW1_FsL0FxUv8NZSh-XUNkVIV9Z2J8GiQYTL7uI1puqpFjlEgNmZqIOHINHKo6y1yXwXM8lsjsMH0ssEqYmf7iMeYMsj35iQJI-6Y5G_44L98TX6SK5rcZx_RfC9JdSox/s1600/interviewing-distribution.png" height="240" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
I don't think there is any correlation between these graphs. I've seen plenty of programmers that have great job-acquisition ability, but poor programming ability. I've also seen plenty of the inverse. </div>
<h2 style="clear: both; text-align: left;">
Burying the Lede</h2>
<div>
If you assume that my anecdotal graphs above are true, then there are probably a lot of bad programmers employed today. In Jacob's talk, he mentions that the US government projects a 1.5 million gap between available jobs and available programmers by 2020. Thus, companies have a high incentive to hope that a bad programmer will become better. In my experience, companies that employ most bad programmers don't know they have bad programmers, and thus are unlikely to fire them, so bad programmers have little incentive to improve. In my 15 years of professional experience, the only times I've ever seen a bad programmer be fired was for insubordination or other issues unrelated to ability.</div>
<h2 style="clear: both; text-align: left;">
TLDR Again</h2>
<div>
10x programmers are probably extremely rare. It is 0.1x programmers that are common. I've interviewed lots of them. I've worked directly with lots of them in my 6 years as a consultant and 4 years suffering in large midwestern corporations. I've also worked with some really good programmers as well. I've never worked with someone that I'd classify as a 10x programmer, but I've met a few 2x programmers.</div>
<h2>
Outsider</h2>
<div>
In Jacob's talk, he mentions that he didn't invent <a href="https://www.djangoproject.com/">django</a>, but rather just happened to be an early user. He further claims to be a mediocre programmer without presenting any evidence. I think Jacob is simply undervaluing himself. I'm not part of the python community at all. I don't follow <a href="https://twitter.com/jacobian">@jacobian</a> on twitter. I could be completely wrong about the people that he's worked with, but based on <a href="https://www.crunchbase.com/person/jacob-kaplan-moss">a quick googling</a>, he's only worked at The Lawrence Journal World (with the inventors of django) and <a href="https://www.heroku.com/">Heroku</a>. I assume that means he never spent 2008 hacking on a massive EJB-based single-use custom web framework from 2002 for an insurance company. I'm not holding up that as a badge of honor or martyrdom, but of a vastly different experience.</div>
<h2>
For the Beginners</h2>
<div>
I agree with Jacob that 10x expectations are unrealistic and are intimidating beginners away from the field. However, a 10x difference in ability is real. We need to communicate to beginners not that they must be 10x badasses, but that most programmers are 0.1x clock-punchers who don't have much desire to improve. Beginners have an amazing opportunity to quickly surpass people with lots more experience. This doesn't require working 60 hours/week every week, though one might be required occasionally. It requires a desire to investigate root causes of problems instead inserting <code>Thread.sleep(1)</code> in your code when you have a race condition. It requires a automating a database upgrade process instead of manually babysitting it every weekend so you can get easy overtime pay. It requires optimizing your build instead of accepting that it takes 2 minutes to redeploy your webapp after a simple JSP change. (These are all real-life 0.1x programmer examples.)<br />
<h2>
Epilogue</h2>
</div>
<div>
In case you think I spent past professional life in an awful gulag, I didn't at all. There were definitely some low points, but I had lots of opportunities to learn a vast array of different technologies, and I got the opportunity to work full time on iOS starting in 2009, which I'm still doing today.</div>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-23666639682898146872015-03-05T21:34:00.000-08:002015-03-05T21:38:02.770-08:00Mozilla Should Build an Android Permissions DelegatorEarlier today, I had a thought:<br />
<blockquote class="twitter-tweet" lang="en">
Android Permissions idea: Proxy with another app that has permissions you need so your permissions don't look suspicious on install.<br />
— Heath Borders (@heathborders) <a href="https://twitter.com/heathborders/status/573596296356872192">March 5, 2015</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
Of course, this wasn't novel:<br />
<blockquote class="twitter-tweet" lang="en">
<a href="https://twitter.com/heathborders">@heathborders</a> See <a href="https://t.co/uJR1D3qNhH">https://t.co/uJR1D3qNhH</a>, pages 2498-2506 for a ContentProvider permissions proxy writeup.<br />
— Mark Murphy (@commonsguy) <a href="https://twitter.com/commonsguy/status/573597422296956928">March 5, 2015</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<blockquote class="twitter-tweet" lang="en">
<a href="https://twitter.com/heathborders">@heathborders</a> We actually looked into that for WebApp (APKs) that use Firefox as runtime. Put perms in WebApp but proxy data to Firefox.<br />
— Mark Finkle (@mfinkle) <a href="https://twitter.com/mfinkle/status/573622213288554497">March 5, 2015</a></blockquote>
However, this doesn't have to be an idea only used for evil. What if there existed a trusted app that exposed all permissions available to other apps at runtime? Mozilla seems like a good candidate to make this. They're a trusted organization dedicated to privacy and openness and they have the technical expertise to pull it off. Let's pretend one exists called Mozilla Services.<br />
<br />
For end users, this could greatly improve the Android experience. Let's use Facebook (which I don't have installed because it requests WAY too many permissions) as an example:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitoCdHwQd1k2AOFT1q2buy_r1QteBZZjHrCVJcXwK64HQ3ybIZkSMvAp3RBOwyismIR_UYnLzewfg26JhOLan6z6QXvlGBNL3-PmgrfYIICC1wzq4bDfZtHCP1d3X8FiBB-mwG0BpNelWA/s1600/Screenshot_2015-03-05-22-58-33.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitoCdHwQd1k2AOFT1q2buy_r1QteBZZjHrCVJcXwK64HQ3ybIZkSMvAp3RBOwyismIR_UYnLzewfg26JhOLan6z6QXvlGBNL3-PmgrfYIICC1wzq4bDfZtHCP1d3X8FiBB-mwG0BpNelWA/s1600/Screenshot_2015-03-05-22-58-33.png" height="320" width="180" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx69JIiJEbmpEhKUrvg7DUA7hRl0H72QWC5R5nH335KwHqkT4nWxgDQH0P8HTlfxQOfYvHovwwdoNsSiTziktQu7F8R9AKNxoFLRCrnxlAx-Ki7mz2tyXZOFOhtk4H_T1Ze0jHcd0LqtpX/s1600/Screenshot_2015-03-05-22-58-37.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx69JIiJEbmpEhKUrvg7DUA7hRl0H72QWC5R5nH335KwHqkT4nWxgDQH0P8HTlfxQOfYvHovwwdoNsSiTziktQu7F8R9AKNxoFLRCrnxlAx-Ki7mz2tyXZOFOhtk4H_T1Ze0jHcd0LqtpX/s1600/Screenshot_2015-03-05-22-58-37.png" height="320" width="180" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Instead of this crazy long permissions list, Facebook could request only the ability to connect to the internet. (This permission is so common that <a href="https://support.google.com/googleplay/answer/6014972#review">Google hides it from the default list</a>.) Then, when Facebook wants to <a href="http://www.geek.com/mobile/facebook-app-now-listens-and-records-audio-when-you-post-updates-from-your-phone-1595873/">do something evil like listen to my microphone when I post an update</a>, it could do so at runtime by sending an Intent to the Mozilla Services App. Mozilla Services could keep an internal list of permissions granted to various apps (which users could revoke at any time). If Facebook hasn't been approved to use the microphone, Mozilla Services could pop up a dialog asking me to allow Facebook to use the microphone. Mozilla Services could then use the microphone and delegate access to the bitstream to Facebook. If I later decide I don't trust Facebook with microphone access, I could open Mozilla Services and remove Facebook's permission.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Of course, Facebook will never adopt this scenario because it already has over 1 billion installs even with all the permissions it requires. However, some smaller app like <a href="https://www.makewonder.com/">Wonder Workshop</a>'s <a href="https://play.google.com/store/apps/details?id=com.makewonder.pathandroid">Path for Dash</a>, which doesn't yet have 500 installs, might want to reduce friction for users, so it could use Mozilla Services to set up its Bluetooth connection.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Maybe you're way more influential than me and can convince Mozilla to build this. <a href="http://careers.mozilla.org/en-US/position/oB2w0fwT">They're hiring Android/iOS engineers...</a></div>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-44335219845572572522015-02-02T15:16:00.001-08:002015-02-02T15:16:42.860-08:00Towards an Ideal Cocoapod Project Structure<h2>
The Situation</h2>
I recently returned to iOS from a year-old Android hiatus. On my last iOS project, I used <a href="http://cocoapods.org/">cocoapods</a> as my dependency manager, but this was bolted onto an existing codebase. I'm starting fresh now, and I want to find a canonical project structure for a cocoapod (think AFNetworking, CocoaLumberjack, etc).<br />
<h2>
The Problem</h2>
<div>
I don't want to have duplicate configuration between an Xcode project and a podspec. Ideally, cocoapods would configure a project with which I can do daily development.<br />
<h2>
The Solution</h2>
</div>
<div>
Development Pods! Specifically, create a demo project for your cocoapod, and use the demo project's <code>Podfile</code> to import your cocoapod into Xcode:</div>
<div>
<br /></div>
<blockquote class="tr_bq">
<b>Using the files from a local path.</b><br />
If you wold like to use develop a Pod in tandem with its client project you can use the path option.<br />
<code style="background-color: #666666;"><span style="color: white;">pod 'MyPod', :path => 'MyPod/MyPod'</span></code><br />
Using this option CocoaPods will assume the given folder to be the root of the Pod and will link the files directly from there in the Pods project. This means that your edits will persist to CocoaPods installations.</blockquote>
<a href="http://guides.cocoapods.org/syntax/podfile.html#pod">http://guides.cocoapods.org/syntax/podfile.html#pod</a><br />
<br />
I created a Single-View iOS App, which yielded a project structure like this:<br />
<code>MyPod.xcodeworkspace/</code><br />
<code>MyPod/MyPod/MyPod.</code>h<br />
<code>MyPod/MyPod/MyPod.m</code><br />
<code>MyPod/MyPod/MyPod-Info.plist</code><br />
<code>MyPod/MyPod.xcodeproj/</code><br />
<br />
The <code>podspec</code> is a supporting file, so it belongs in <code>MyPod/MyPod</code> with <code>MyPod-Info.plist</code> and friends. Now, if I want to modify my cocoapod's configuration by adding an AFNetworking dependency, I only need to change my <code>podspec</code> and run <code>pod install</code>.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-84272292618656334672013-09-28T22:17:00.001-07:002013-09-28T22:17:27.028-07:00Cocoapods - ARGV - Returns Options as a Hash, OCMock only for Tests target.Tonight I actually made my cocoapods objc port use cocoapods. Most of the point of this adventure is for me to deeply learn cocoapods. I initially wanted to replace some<a href="https://github.com/hborders/CLAide/blob/ARGV/CLAide%20Tests/ARGV_Tests.m#L12-16"> manually written stubs in my first ARGV test</a> with <a href="http://ocmock.org/">OCMock</a>, but it OCMock doesn't support stubbing <code>-[NSObject description]</code>, so I didn't actually need it. I imagine I'll need OCMock at some point, and it was also a good exercise in learning <a href="https://github.com/hborders/CLAide/blob/objc/Podfile#L2-5">how to setup cocoapods dependencies only for specific targets</a>, so I left it in.<br />
I also tried implementing the "returns options as a hash" spec, but ran out of time. <a href="https://twitter.com/phatblat/status/383828737717858304">Ben Chatelain suggested</a> I use <a href="https://github.com/NSError/ArgumentParser">FSArgumentParser</a>:<br />
<blockquote class="twitter-tweet">
<a href="https://twitter.com/heathborders">@heathborders</a> ArgumentParser is worth a look to simplify the ARGV, but it may still have issues
<a href="http://t.co/kv8MPaT3PB">http://t.co/kv8MPaT3PB</a><br />
— Ben Chatelain (@phatblat) <a href="https://twitter.com/phatblat/statuses/383828737717858304">September 28, 2013</a></blockquote>
but I don't think that's going to work. However, FSArgumentParser depends upon <a href="https://github.com/beelsebob/CoreParse">CoreParse</a>, and that looks like it'll work out great. I'll probably use FSArgumentParser as an example of how to use CoreParse for my purposes, so I think Ben's suggestion will pay many dividends. I love knowing smart people.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-51885718369652720042013-09-27T21:38:00.002-07:002013-09-27T21:38:59.148-07:00Cocoapods adventuresWe've started using <a href="http://cocoapods.org/">Cocoapods</a> at work, and it seems like a really great system. However, it is written in ruby, and I hypothesize that it would get more participation from the community if it was written in Objective-C. Also, since Cocoapods is a specification as well as a system, it would benefit from a separate (though in this case not clean-room) implementation. Thus, I'm going to rewrite Cocoapods in Objective-C and blog about my journey along the way.<br />
Thankfully, Cocoapods looks pretty modular, and it looks like it has good tests. I'm starting with <a href="https://github.com/CocoaPods/CLAide">CLAide</a>, which is Cocoapods' command-line aide. This has <a href="http://rspec.info/">RSpec</a> tests, which I know nothing about, but I can generally figure out what they're doing just by reading the text.<br />
Tonight, I just wanted to start something. I wasn't too concerned about crazy progress. I simply cloned CLAide and figured out how to run the existing RSpec tests. I found the .travis.yml file with a script command that looked promising, so I tried running that, and installed required gems (bundler, rspec) until it worked.<br />
Next, I just converted the first two tests in the first spec (argv_spec.rb). I'm doing at least one commit for each test I convert. Also, I'm keeping all this work on a separate branch. Eventually, I'll just have a parallel Foundation command-line tool project that I'll keep up to date.<br />
Tomorrow, I'll tackle the first real piece of parsing necessary. Hopefully, I'll have ARGV converted by Sunday night.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-39277593069754710142013-06-15T20:44:00.003-07:002013-06-15T20:46:49.598-07:00All the smart kids are writing blog posts about exceptionsSince all the <a href="http://blog.jessitron.com/2013/06/whats-dirtier-than-comments-exceptions.html">smart</a> <a href="http://marioaquino.blogspot.com/2013/06/styles-of-handling-conditional-logic.html">kids</a> are writing blog posts about exceptions, I figure if I write one, I might be considered smart by association. :)<br />
<br />
I favor automation in all things. I will happily supply metadata with my code that will allow it to be automatically verified to be correct, or at least more correct than it could be without the metadata. This colors my viewpoint on exceptions.<br />
<br />
This all started because of Craig Buchek's tweet:
<br />
<blockquote class="twitter-tweet">
<a href="https://twitter.com/Adkron">@Adkron</a> <a href="https://twitter.com/jessitron">@jessitron</a> Uh, no. It's not trying to raise an exception. Just a reminder that it might. The code: user = c.get_setting('username')<br />
— Craig Buchek (@CraigBuchek) <a href="https://twitter.com/CraigBuchek/statuses/344583846722957312">June 11, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
I prefer code that enumerates exactly what it will return and how it might fail via the type system. I used to prefer checked exceptions everywhere for this, but I've since changed to just returning a either a good return value or an error.
<br />
Old Java:
<br />
<pre>class Foo {
Foo foo() throws FooException {
if (Math.random() < .5) {
throw new FooException();
} else {
return new Foo();
}
}
Foo bar(Foo foo) throws FooException {
if (Math.random() < .5) {
throw new FooException();
} else {
return foo.foo();
}
}
String baz() throws BazException {
try {
Foo foo = foo();
Foo barFoo = bar(foo);
return "I ran the gauntlet with " + barFoo;
} catch (FooException f) {
throw new BazException(f);
}
}
}
</pre>
<br />
With this code, you can capture all your handling for common errors in one place, and because FooException is a checked exception, the compiler will happily tell you if you forget to handle your error cases. Yay!
<br />
<br />
However, errors are data just like everything else, and they don't need to be shunted off into a separate world. One might assume that if we remove exceptions, we'll end up with a lot of annoying if checks:
<br />
<pre>class Foo {
Either<Foo, FooException> foo() {
if (Math.random() < .5) {
return new Either<>(new FooException());
} else {
return new Either<>(Foo);
}
}
Either<Foo, FooException> bar(Foo foo) throws FooException {
if (Math.random() < .5) {
return new Either<>(new FooException());
} else {
return foo.foo();
}
}
Either<String, FooException> baz() throws BazException {
Either<Foo, FooException> eitherFooOrFooException = foo();
if (eitherFooOrFooException.left()) {
Either<Foo, FooException> eitherBarFooOrFooException = bar(eitherFooOrFooException.left());
if (eitherBarFooOrFooException.left()) {
return "I ran the gauntlet with " + eitherBarFooOrFooException.left();
} else {
return new Either<>(new BazException(eitherBarFooOrFooException.right()));
}
} else {
return new Either<>(new BazException(eitherFooOrFooException.right()));
}
}
}
</pre>
<br />
It doesn't have to be that way. <a href="http://blog.jessitron.com/2013/06/whats-dirtier-than-comments-exceptions.html">Jessica Kerr describes how in detail</a>. However, Java idioms and language limitations do make these functional styles difficult. So, if you're in Java-land, I won't look down upon you for sticking with Exceptions, as long as they're checked.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com3tag:blogger.com,1999:blog-4861730248808553332.post-83701269103343134422012-12-01T22:02:00.000-08:002012-12-01T22:02:36.920-08:00Objective-C Does Not Belong Outside of MobileThe power of Objective-C comes from its tight and nearly seamless integration with C. The power of C comes from its focus on efficiency and performance and its quasi-portability. Both of these qualities are essential for mobile development. Mobile devices run on a number of different platforms with different binary types (Android uses ELF, while iOS uses Mach-O) and generally have tight clock and memory constraints. Given these compromises, C is a great choice.<br />
<br />
However, C doesn't support object-oriented niceties that were fashionable 10-15 years ago, and it doesn't support functional niceties that are en vogue now. Objective-C does an passable job at the former is trying to get better at support for the latter with the help of <a href="https://github.com/github/ReactiveCocoa">ReactiveCocoa</a> and friends.<br />
<br />
So, given that Objective-C minimally satisfies the requirements of a modern language, should we extend it to the web? I don't think so. The web doesn't operate under the same CPU and memory constraints, so we can use some of that power to make developers more efficient. In cases where bottlenecks occur, most programming environments still support C development. Objective-C may make sense there. However, most developers aren't building Facebook, and <a href="https://developers.facebook.com/blog/post/2010/02/02/hiphop-for-php--move-fast/">Facebook has even figured out a way to make its code more efficient while harnessing the power of its army of highly skilled PHP developers.</a><br />
<br />
<a href="http://kevinlawler.com/objective-c">Kevin Lawler makes a case for Objective-C on the server.</a> I'll break down my disagreements with his article below. I'll use Java as a counterexample since it is currently the dominant player and is widely deadpanned as being an awful language. If Objective-C can't beat Java, it doesn't stand a chance against ruby, python, javascript, clojure, scala, or any other server-side cult hits.<br />
<h4>
Objective-C is not a joy:</h4>
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">In the past few years, quietly, almost invisibly, Apple has transformed its Objective-C language into the best language available. I have been working with Objective-C since the release of the iPhone App Store in 2008. In that time Objective-C has evolved from a clunky, boilerplate-heavy language, into a tight, efficient joy. It is an amazing tool. Anything that I would not write in C I would want to write in Objective-C, were support available.</span></blockquote>
No. Objective-C is not an efficient use of developer time, nor is it a joy. There is still a ton of boilerplate present. I'm sure there are many other things I hate about Objective-C the language, but these are just a few things I came up with off the top of my head.<br />
<ul>
<li>I must declare both an <code>@interface</code> and <code>@implementation</code> for every class.</li>
<li>The compiler doesn't support circular references, you must forward declare classes and protocols that are circularly referenced with <code>@class</code> and <code>@protocol</code>.</li>
<li>There is no support for namespaces, leading to names like <code> kBluetoothAMPManagerCreatePhysicalLinkResponseAMPDisconnectedPhysicalLinkRequestReceived</code></li>
<li>There are no private methods. There is no way to be sure that a subclass won't accidentally override one of my internal methods simply by reusing one of my names.</li>
<li>No type variables (generics)</li>
<li>Can't add nil to Foundation collections</li>
<li>No support for inner classes</li>
<li>It is a superset of C, so everything you hate about C goes here too.</li>
</ul>
<h4>
A paragraph full of fail:</h4>
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">To understand the opportunity facing Objective-C it will help to summarize where Java fails. The original promise of Java was that an application written once would compile and deploy on any architecture. Ignoring that this is false, web shops don't use Java for this reason. Platform inconsistency is an issue for almost no one, and it was never an issue to port correct C/C++ code, universal compatibility being the original promise of C as well. This promise however spurred the creation of the JVM, which was Java's first mistake. The JVM is a nonsense abstraction over the assembly and UNIX system layer. Now code runs through an additional layer, which </span><a href="http://stackoverflow.com/a/2163570/365478" style="background-color: white; border: 0px; color: #006699; font-family: Georgia, serif; font-size: 16px; font: inherit; line-height: 24px; margin: 0px; padding: 0px; text-decoration: initial; vertical-align: baseline;">can be slow</a><span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">, and system interactions must be translated through an otherwise pointless, just-for-this-purpose Java API. In the ideal case, this API replicates the entirety of the UNIX system layer in Java-ese, obscuring any helpful C idioms or UNIX-system knowledge in the process, and creating a pointless set of new knowledge to understand. In the less than ideal case, the API fails to implement system-level functionality and creates a barrier between the application and the machine.</span></blockquote>
So much is wrong with this paragraph.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">Ignoring that this is false, web shops don't use Java for this reason.</span></blockquote>
There are certainly edge cases, but this is far from false. Java is very much write-once run everywhere. More importantly, it is compile once, link and run everywhere. I'll grant you that some Java libraries have crazy mavenized builds that can take way too long to run, but that isn't Java's fault. Code that you write in Java will compile the same way on any machine and run basically the same way on any other machine, regardless of endianness, instruction width, or operation system. Web shops depend on this to easily consume libraries from all over the Java ecosystem. I invite Mr. Lawler to look at the amount of platform specific code in the average Apache Jakarta project. I'll bet it is effectively zero.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">Platform inconsistency is an issue for almost no one, and it was never an issue to port correct C/C++ code, universal compatibility being the original promise of C as well.</span></blockquote>
I'm hardly a C badass, but I'm pretty good at Java. I'm not at all confident in my ability to write correct platform independent C code. Thankfully, I only target iOS, and I only build with xcode, just like every other iOS developer out there. Nearly all iOS developers build with Clang, and most are on one of a few key versions. I can't imagine trying to build a reusable library that would compile and link with all the different C/C++ compilers/linkers and run on nearly any system.<br />
<br />
Even if we ignore the need to write universally compatible code, I would have to invest great amounts of time in consuming any library that wasn't written specifically for my platform. If I wanted to use Apache commons-codec, but it was written on 32-bit Windows, I'd be very skeptical about consuming it on 64-bit Mac without a thorough review. I have no such concern about Java. I can't believe it is 2012, and I have to make that argument.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">This promise however spurred the creation of the JVM, which was Java's first mistake. The JVM is a nonsense abstraction over the assembly and UNIX system layer.</span></blockquote>
No. The JVM is a portable UNIX system layer that runs everywhere. The JVM brought UNIX to windows, and its portable bytecode has enabled an <a href="http://en.wikipedia.org/wiki/List_of_JVM_languages">amazing ecosystem of languages</a>, most of which has the power to interoperate.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">Now code runs through an additional layer, which </span><a href="http://stackoverflow.com/a/2163570/365478" style="background-color: white; border: 0px; color: #006699; font-family: Georgia, serif; font-size: 16px; font: inherit; line-height: 24px; margin: 0px; padding: 0px; text-decoration: initial; vertical-align: baseline;">can be slow</a><span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">, and system interactions must be translated through an otherwise pointless, just-for-this-purpose Java API.</span></blockquote>
I guess Mr. Lawler has never heard of the <a href="http://www.parleys.com/#id=1592&st=5">Hotspot JVM's amazing inlining technologies in its JIT compiler</a>. Also, he links to a stackoverflow answer that basically says Java is not slow at all, though the answer does list some downsides with respect to memory and startup time, both of which aren't issues for the web.<br />
<h4>
A few more nits to pick:</h4>
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">Garbage collection makes execution (and memory usage) unpredictable. You cannot postpone garbage collection forever. The more critical the execution, the more you want to postpone garbage collection, but the longer you postpone garbage collection, the more of a problem it will eventually be. This is a disaster for applications that need to scale.</span></blockquote>
There is truth here, but <a href="http://www.infoq.com/interviews/click-gc-azul">Azul's Zing</a> basically blows it all away.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">Oracle now owns Java and is a hostile entity. Java is done. Its future as a product is finished.</span></blockquote>
Although <a href="http://blog.joda.org/2010/12/is-jcp-dead_8808.html">Oracle decimated the JCP</a>, they have been a terrific steward of Java for features. They actually shipped Java 7, which greatly improved performance and includes many new features (<a href="http://jcp.org/en/jsr/detail?id=203">including lots of missing UNIX APIs</a>).<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">As an aside, tying any new language to the Oracle JVM is destined to be a mistake, for reasons previously mentioned.</span></blockquote>
The JVM is a great place to run a new language. JRuby applications saw <a href="http://blog.jruby.org/2011/12/getting_started_with_jruby_and_java_7/">free performance gains of up to 30%</a> just from moving from Java6 to Java7.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">In practice, object-oriented programming lets large teams of competent programmers build usable software. The same is rarely said for functional languages. In cases where functional language applications do succeed, they are often treated as prototypes and rewritten.</span></blockquote>
I can point you to a whole <a href="http://clojure-conj.org/">army</a> <a href="http://www.erlang-factory.com/">of</a> <a href="http://days2012.scala-lang.org/">people</a> that would disagree with that. I know of <a href="http://www.revelytix.com/">3</a> <a href="https://twitter.com/ryan_richt/status/258762365489786880">different</a> <a href="http://www.riotgames.com/">companies</a> just in St. Louis that build very big systems with functional platforms. Of course, this is only anecdotal evidence, but I'm sure functional languages are taking off if a small town like St. Louis has such a good showing. Of course, twitter famously uses functional languages for many things, including <a href="http://clojurewest.org/training-cascalog/">processing its massive logs</a>.<br />
<h4>
The lines that caused me to write this blog post:</h4>
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">5. Xcode is an excellent IDE, with tolerably good git support</span></blockquote>
This line just killed me. Xcode is <a href="http://www.textfromxcode.com/">the biggest piece of shit modern IDE I've ever used</a>. I outlined my hatred in <a href="https://github.com/hborders/Xcode-Sucks/blob/master/Xcode-Sucks.markdown">a presentation</a> I gave to <a href="http://lambdalounge.org/2012/07/05/things-i-hate-about-you/">Lamda Lounge</a>. If Mr. Lawler thinks it is excellent, he's clearly never used <a href="http://eclipse.org/jdt/">Eclipse JDT</a> or <a href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a>, and he's never been amazed at swapping hot code at runtime with <a href="http://zeroturnaround.com/software/jrebel/">JRebel</a>. He must not have ever wanted to use a structural code formatter, either. I'm sure he doesn't care about creating plugins or modifying the tools he uses. I doubt he wants a <a href="http://fixradarorgtfo.com/">transparent bug reporting system</a>.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">IDE auto-completion works wonderfully.</span></blockquote>
No, it doesn't. I just barely works. If there are any compilation errors in the class, the autocomplete fails. It stupidly suggests methods from all over the various C APIs that I've never used and I doubt would ever be applicable to my code. It never prioritizes local variables or methods that I most often use. "NSS" doesn't complete to "NSString", it completes to "NSStream". "NSLo" becomes "NSLoadedClasses".<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #333333; font-family: Georgia, serif; font-size: 16px; line-height: 24px;">The library import process is less tedious than in Java.</span></blockquote>
I think Mr. Lawler is trolling me. Xcode has no auto-import at all. In Eclipse, if I type "Set", "import java.util.Set;" is automatically added at the top. I would love this feature in Xcode. If I want a library in Xcode, I have to use the mouse to navigate through 5 modal operations.<br />
<h3>
Still Good For Mobile</h3>
<div>
Again, mobile development operates under a different set of constraints. We need C on mobile, and we need a modern superset of C to build mobile applications. Objective-C is a decent choice. As I outlined above, it has warts, but they are tolerable given the constrained environment of mobile. Thanks for journeying with me on my insane screed.</div>
Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com1tag:blogger.com,1999:blog-4861730248808553332.post-58947299338798333822012-07-06T13:01:00.000-07:002012-07-06T13:01:46.730-07:00Categorizing your radarsWhen you encounter a bug in Apple's iOS code, you need to <a href="https://bugreport.apple.com/">report it</a>. I was always confused about the Product against which I should report my bug. There are 3 categories that made sense to me:<br />
<br />
<ul>
<li>Developer Tools</li>
<li>iPad SDK</li>
<li>iPhone SDK</li>
</ul>
<div>
Thankfully, former Apple Developer Evangelist <a href="http://twitter.com/jury">@jury</a> cleared it up for me:</div>
<blockquote class="twitter-tweet" data-in-reply-to="221320195342475264"><p>@<a href="https://twitter.com/heathborders">heathborders</a> File them against the SDK where you're finding them</p>— Michael Jurewitz (@Jury) <a href="https://twitter.com/Jury/status/221320619814424579" data-datetime="2012-07-06T19:12:02+00:00">July 6, 2012</a></blockquote>
<script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-in-reply-to="221322432693280768"><p>@<a href="https://twitter.com/heathborders">heathborders</a> An SDK is everything related to development for that “thing” — APIs, tools, apps, etc.</p>— Michael Jurewitz (@Jury) <a href="https://twitter.com/Jury/status/221328375430647811" data-datetime="2012-07-06T19:42:51+00:00">July 6, 2012</a></blockquote>
<script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-in-reply-to="221329699274620928"><p>@<a href="https://twitter.com/heathborders">heathborders</a> Just indicate in the bug which devices it affects.</p>— Michael Jurewitz (@Jury) <a href="https://twitter.com/Jury/status/221330108420587522" data-datetime="2012-07-06T19:49:44+00:00">July 6, 2012</a></blockquote>
<script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
Basically, use iPad SDK if you find it in the iPad Simulator/device, use iPhone SDK if you find it in the iPhone Simulator/device. Don't double-report the bug, indicate that it exists in multiple categories in the bug text.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-23090458101555874522012-06-18T21:35:00.000-07:002012-06-18T21:50:12.539-07:00Abstract Methods on Legacy Objects Using CategoriesLet's say we have the following classes:<br />
<br />
<br />
<pre>@interface HBAbstractLegacyNode : NSObject
@end
@interface HBChildNode : HBAbstractLegacyNode
@property (nonatomic, strong) NSString *childProperty;
@end
@interface HBParentNode : HBAbstractLegacyNode
@property (nonatomic, strong) NSString *parentProperty;
@end</pre>
<br />
<br />
<br />
If we want to add a template method onto
<code>HBAbstractLegacyNode</code>, we ordinarily, just alter our classes thusly:<br />
<br />
<br />
<pre>@interface HBAbstractLegacyNode : NSObject
- (void) templateMethod;
- (NSString *) abstractishMethod;
@end
@implementation HBAbstractLegacyNode
- (void) templateMethod {
NSLog(@"templateMethod: %@", [self abstractishMethod]);
}
- (NSString *) abstractishMethod {
[NSException raise:@"Override" format:@"%@ should override %@", NSStringFromClass(self), NSStringFromSelector(_cmd)];
return nil;
}
@end
@implementation HBChildNode
- (NSString *) abstractishMethod {
return self.childProperty;
}
@end
@implementation HBParentNode
- (NSString *) abstractishMethod {
return self.parentProperty;
}
@end</pre>
<br />
<br />
<br />
But what if we're dealing with legacy code or a 3rd party library, and can't or don't want to modify our existing classes? Then, we can utilize categories to add methods, and use protocols to get some compile-time type safety.<br />
<br />
<br />
<pre>@protocol HBOptionalAbstractish <nsobject>
@optional
- (NSString *) abstractishMethod;
@end
@protocol HBAbstractish <hboptionalabstractish>
@required
- (NSString *) abstractishMethod;
@end
@interface HBAbstractLegacyNode(HBTemplate)
- (void) template;
@end
@interface HBParentNode(HBAbstractish)<hbabstractish>
@end
@interface HBChildNode(HBAbstractish)<hbabstractish>
@end
@implementation HBParentNode(HBAbstractish)
- (NSString *) abstractishMethod {
return self.parentProperty;
}
@end
@implementation HBChildNode(HBAbstractish)
- (NSString *) abstractishMethod {
return self.childProperty;
}
@end
@interface HBAbstractLegacyNode(HBOptionalAbstractish)<hboptionalabstractish>
@end
@implementation HBAbstractLegacyNode(HBOptionalAbstractish)
@end
@implementation HBAbstractLegacyNode(HBConsumerCodeTemplate)
- (void) template {
NSLog(@"template: %@", [self abstractishMethod]);
}
@end</hboptionalabstractish></hbabstractish></hbabstractish></hboptionalabstractish></nsobject></pre>
<br />
<br />
<br />
We define two parallel protocols, one whose methods are optional, and one whose methods are required. <a href="http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/chapters/occategories.html">Apple's Category Documentation</a> says:<br />
<blockquote>
There’s no limit to the number of categories that you can add to a class, but each category name must be different, and each should declare and define a different set of methods.
</blockquote>
<br />
<a href="http://stackoverflow.com/a/5272612/9636">Further restrictions exist (I can't find a link to Apple documentation beyond this stackoverflow answer, please help me find a link to real docs)</a>:<br />
<blockquote>
<br />
<div style="background-color: transparent; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; text-align: left; vertical-align: baseline; word-wrap: break-word;">
Although the Objective-C language currently allows you to use a category to override methods the class inherits, <strong style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">or even methods declared in the class interface, you are strongly discouraged from doing so</strong>. A category is not a substitute for a subclass. There are several significant shortcomings to using a category to override methods:</div>
<ul style="background-color: transparent; border: 0px; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 1em 30px; padding: 0px; text-align: left; vertical-align: baseline;">
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; word-wrap: break-word;"><div style="background-color: transparent; border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">super</code>. However, <strong style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">if a category overrides a method that exists in the category's class, there is no way to invoke the original implementation</strong>.</div>
</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; word-wrap: break-word;"><div style="background-color: transparent; border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<strong style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline;">A category cannot reliably override methods declared in another category of the same class.</strong></div>
<div style="background-color: transparent; border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
This issue is of particular significance because many of the Cocoa classes are implemented using categories. A framework-defined method you try to override may itself have been implemented in a category, and so which implementation takes precedence is not defined.</div>
</li>
<li style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; word-wrap: break-word;"><div style="background-color: transparent; border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the <code style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; margin: 0px; padding: 1px 5px; vertical-align: baseline;">windowWillClose:</code> delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes.</div>
</li>
</ul>
</blockquote>
<br />
I interpret the above to mean we should not override methods from categories. Thus, we define the optional protocol who we will implement with a category on our superclass, <code>HBAbstractLegacyNode</code>. Then, we'll implement the required protocol on each of our subclasses. <br />
<br />
Unfortunately, we don't have complete compile-time type safety. We must manually ensure that the methods in <code>HBAbstractish</code> and <code>HBOptionalAbstractish</code> have matching signatures, and we must manually ensure that we create category implementations for each new subclass we create. Thus, we don't get complete fidelity with <code>abstract</code> methods you find in Java, but we get close.<br />
<br />
Declaration and implementation order matter to ensure that the compiler doesn't think subclasses have inherited an implementation from their superclass. The protocol declarations must come first, but the subclass interface and implementations must come before the superclass'. If the superclass' interface comes before the subclass' implementation, the compiler will think the subclass already has an implementation from the superclass and will not warn us if we haven't provided an implementation. Since the superclass implements the optional protocol and we don't provide any methods in its implementation, the superclass actually provides nothing to its subclasses.<br />
<br />
This is a lot of work to get a few helpful hints from the compiler, but when you have an enormous codebase spanning hundreds of files, all these checks (in concert with unit tests), go a long way towards stopping stupid errors.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-11708019402628471382012-02-09T22:41:00.000-08:002012-02-10T11:08:51.033-08:00iOS 5.0 MKMapView (MapKit MapView) Edge CasesThe following are notes from my adventures implementing complex custom callouts in an MKMapView on iOS 5.0.<br />
<br />
<ul><li>The selected MKAnnotationView is brought to the front of the group.</li>
<li>When the selected MKAnnotationView is deselected, other undefined annotations may appear in front.</li>
<li>Calling -[MKMapView selectAnnotation:animated:] on an annotation with a disabled MKAnnotationView will not select the MKAnnotationView. </li>
<ul><li>The MKMapView will not call -[MKMapViewDelegate mapView:didSelectAnnotationView:].</li>
</ul><li>If MKAnnotationViews overlap and one is selected, touching the selected one will select an unselected one. Since custom callouts must be implemented as ordinary MKAnnotationViews, you must disable all MKAnnotationViews behind a callout MKAnnotationView if you want the user to be able to interact with UIControls inside your callout MKAnnotationView</li>
<li>Any UIControls in your MKAnnotationView must exist within your MKAnnotationView's frame. Otherwise, when the user attempts to touch them, the map will think the user touched outside the MKAnnotationView and deselect your MKAnnotationView.</li>
<li>You may change the frame of your MKAnnotationView after the MKMapView calls -[MKMapViewDelegate mapView:viewForAnnotation:] and -[MKMapViewDelegate mapView:didAddAnnotationViews:]. However, you can't change the -[MKAnnotationView centerOffset]. So, if you change the frame size, it needs to grow equally in all directions.</li>
<ul><li>When you don't grow the MKAnnotationView's frame evenly, it will appear to look fine at first, but when you zoom the map, it will snap to its old centerOffset.</li>
</ul></ul>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-45243151177222034622010-11-13T08:27:00.000-08:002010-11-13T08:29:33.448-08:00Consolidated VMware VMDKsI just consolidated a 25GB VMware virtual machine into 10GB by consolidating unused snapshot virtual disks. <a href="http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1020000">This vmware faq explains how to do it extremely well.</a>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-71032328404160976462010-05-18T07:38:00.000-07:002010-05-18T07:52:29.400-07:00Edited value not of required format!I'm using the xcode predicate editor to create a core data fetched property, and Apple's developer tools have proved inherently unusable yet again.<br /><br />For a little back-story, I have some reference data, and my user can mark certain pieces of the reference data as favorites. I cannot store my favorites data in the same NSPersistentStore as my reference data. If I did, I couldn't updated my reference data file without migrating my favorites data out. Thus, I'm splitting my favorites data and reference data into separate NSPersistentStores. According to <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW5">Apple's CoreData Programming Guide Cross-Store Relationships section</a> I cannot have a relationship that spans two persistent stores. I need to use a <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW7">fetched property</a>.<br /><br />Now you're caught up. When you create a fetched property, you have to create a predicate to use to find the entity the fetched property represents. This <span style="font-style:italic;">seems</span> straightforward enough, but I kept getting this cryptic message "Edited value not of required format!" After some googling, I found the <a href="http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeCoreDataTools/Articles/xcdPredicateBuilder.html#//apple_ref/doc/uid/TP40006853-SW6">answer</a>.<br /><br />Basically, the editor defaults to expecting a constant value rather than a variable value. To switch to a variable, right-click in the empty space between the text field and the plus/minus buttons. Of course, a drop-down menu would be much better, but I never accused apple of having good tools.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-71874698164378199662010-04-26T15:08:00.000-07:002010-04-26T20:27:53.478-07:00Bootstrapping Buckminster & Subclipse with P2 DirectorOn my current project at work, we are changing from using PDE-Build to create our Eclipse RCP product to using Buckminster. <a href="http://www.ralfebert.de/blog/eclipsercp/rcp_builds/">I found a very valuable tutorial to get me started</a>, but I kept getting exceptions like these:<br /><br /><code><br />ERROR: Could not instantiate provider org.tigris.subversion.subclipse.core.svnnature for project com.foo.<br />org.eclipse.team.core.TeamException: Could not instantiate provider org.tigris.subversion.subclipse.core.svnnature for project com.asolutions.soaf.validation.ws.documentation.test.<br />at org.eclipse.team.core.RepositoryProvider.mapNewProvider(RepositoryProvider.java:165)<br />at org.eclipse.team.core.RepositoryProvider.mapExistingProvider(RepositoryProvider.java:235)<br />at org.eclipse.team.core.RepositoryProvider.getProvider(RepositoryProvider.java:507)<br />at org.eclipse.team.internal.core.TeamHookDispatcher.getProvider(TeamHookDispatcher.java:97)<br />at org.eclipse.team.internal.core.TeamHookDispatcher.getRuleFactory(TeamHookDispatcher.java:105)<br />at org.eclipse.core.internal.resources.Rules.factoryFor(Rules.java:92)<br />at org.eclipse.core.internal.resources.Rules.modifyRule(Rules.java:144)<br />at org.eclipse.core.internal.resources.Project.touch(Project.java:1191)<br />at org.eclipse.jdt.internal.core.SetContainerOperation.executeOperation(SetContainerOperation.java:115)<br />at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:728)<br />at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1975)<br />at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:793)<br />at org.eclipse.jdt.core.JavaCore.setClasspathContainer(JavaCore.java:4842)<br />at org.eclipse.pde.internal.core.PluginModelManager$UpdateClasspathsJob.run(PluginModelManager.java:57)<br />at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)<br /><br /></code><br /><br />The solution is to install subclipse, but doing so within Buckminster is painful because you can only specify a single repository location from the command line. Subclipse has a lot of dependencies that already exist in a default eclipse install, but are missing from buckminster-headless, so I needed to specify multiple repositories.<br /><br /><a href="http://www.eclipse.org/downloads/download.php?file=/tools/buckminster/products/director_latest.zip">p2 director</a> to the rescue!<br /><br />In the tutorial, <a href="http://www.ralfebert.de/blog/eclipsercp/rcp_builds/#hudson">there is a section on bootstrapping buckminster with p2 director</a>. The tutorial loads just the buckminster command-line application from p2 and then uses the buckminster command-line application to load more features into itself. This is convenient when all features and dependencies exist within a single repository, but as I said above, this is not my situation.<br /><br />Assuming you are using bash and have p2 director installed, here is the command:<br /><br /><code><br />director/director\<br />-r http://download.eclipse.org/tools/buckminster/headless-3.6,http://download.eclipse.org/releases/helios/,http://subclipse.tigris.org/update_1.6.x\<br />-d `pwd`/buckminster-headless-3.6/\<br />-p Buckminster\<br />-i org.eclipse.buckminster.cmdline.product\<br />-i org.eclipse.buckminster.core.headless.feature.feature.group\<br />-i org.eclipse.buckminster.pde.headless.feature.feature.group\<br />-i org.tigris.subversion.subclipse.feature.group\<br />-i org.tigris.subversion.clientadapter.svnkit.feature.feature.group<br /></code>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com1tag:blogger.com,1999:blog-4861730248808553332.post-2006553012212229992010-02-04T19:44:00.000-08:002010-02-04T19:57:34.816-08:005 Questions ResponseIn response to <a href="http://twoguysarguing.wordpress.com/2010/02/04/the-revenge-of-the-5-questions/">Ben Lee's Five Questions</a>:<br /><br /><ol><blockquote> <li><em>What are you currently hacking on?</em></li> <li><em>What are you currently getting better at?</em></li> <li><em>What do you do when your computer is asleep?</em></li> <li><em>Describe that ‘big fish’ project that’s been stewing in your brain.</em></li> <li><em>What are you gonna post about this coming week?</em></li> </blockquote></ol><ol><li>JAXB, JAX-RS, Google App Engine for a real-time rating app I'm building with <a href="http://uberu.com/">Mike Gaffney</a>.</li><li>C/Objective-C. At work, I'm building a locator iPhone app for a fortune 500 company, and I'm running into all kinds of low-level issues that Java abstracts away from me. I can't help but feel like a badass when I see registers in my debugger.<br /></li><li><a href="http://stlgac.com/">Hurling</a>, play with my <a href="http://picasaweb.google.com/heath.and.katie.borders.family/MiscFamily#">wife and son</a>.</li><li>In conjunction with #1, I'm building a real-time rating web service in preparation for a hackfest for my <a href="http://groups.google.com/group/stl-mobile-dev">local mobile development group</a>.</li><li>Probably nothing. I usually just use this blog as a public place to store answers to annoying technical problems. Entries should probably be cross-posted on <a href="http://stackoverflow.com">stackoverflow</a> as questions/answers.<br /></li></ol>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com3tag:blogger.com,1999:blog-4861730248808553332.post-11271566347855997002009-12-28T22:25:00.000-08:002009-12-28T22:41:56.959-08:00Disabling Firefox Preview in AptanaEclipse uses xulrunner to embed mozilla firefox within SWT applications. <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=274197">Unfortunately, xulrunner does not work with 64 bit cocoa (cocoa-x64).</a> I'm trying to do Palm Pre development, so I don't need to preview my html in firefox. In fact, previewing in Safari is probably better anyway since, like the pre browser, it is webkit-based.<br /><br />To disable Firefox preview, and stop errors like this:<br /><pre>(Build 1.2.7.024747) [ERROR] Unable to create Firefox browser control<br />No more handles (java.lang.UnsatisfiedLinkError: Could not load SWT library. Reasons:<br /> no swt-xulrunner-cocoa-3624 in java.library.path<br /> no swt-xulrunner-cocoa in java.library.path<br /> Can't load library: /var/folders/Az/Az+0r2ubHtm3wMGMatRuQE+++TI/-Tmp-/swtlib-64/libswt-xulrunner-cocoa-3624.jnilib<br /> Can't load library: /var/folders/Az/Az+0r2ubHtm3wMGMatRuQE+++TI/-Tmp-/swtlib-64/libswt-xulrunner-cocoa.jnilib<br />)<br /></pre>and this:<br /><pre>(Build 1.2.7.024747) [ERROR] (Build 1.2.7.024747) [ERROR] Unable to create Firefox browser control<br />No more handles [Could not detect registered XULRunner to use]<br /></pre>Go to the <code>Window->Preferences->Aptana->Editors->HTML->Preview</code> preference page and uncheck Firefox.<br /><br />If you want to use xulrunner with eclipse out of the box, you must use eclipse carbon 32-bit. If you want to be a little more adventurous, <a href="http://support.aptana.com/asap/browse/STU-4443">an aptana bug report</a> claims that xulrunner is a universal binary and runs on carbon and cocoa 32-bit. I haven't tried to verify this.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-22133600020524811572009-10-05T12:13:00.000-07:002009-10-05T12:18:02.288-07:00XCode Beach Ball Lock Up While Running Unit TestsI downloaded the iphone unit test calculator example project, <a href="http://developer.apple.com/iphone/library/samplecode/iPhoneUnitTests/index.html#//apple_ref/doc/uid/DTS40008868">iPhoneUnitTests</a>. I followed the included directions, and my XCode locked up with a beach ball. I'm running OS X 10.6 and XCode 3.2. According to <a href="http://www.artin.org/geekblog/2009/09/xcode-snow-leopard-logical-unit-tests-hanging/">this article</a>, there is a problem with XCode's regex parsing of the test completion dates for GMT-5:00. Since I'm in Central Daylight time, I am affected. The simple solution is to switch your time zone to Pacific.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-65389360990765211932009-04-09T21:30:00.001-07:002009-04-09T21:38:59.189-07:00VmWare Fusion Shared folders in CentOS GuestI'm working on a personal project that requires RHEL, so I'm using CentOS as a free substitute. Using the default options for RHEL5 on fusion didn't work. Nothing was showing up in /mnt/hgfs, which is where shared host folders should show up. Within the steps of <a href="http://wiki.oracle.com/page/Installing+Oracle+11g+on+CentOS+under+VMWare+on+a+Macbook?t=anon">this tutorial</a>, I found the trick. I needed to disable SELinux, which means I needed to manually install CentOS rather than using fusion's easy install option.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-37844756420472704582009-03-29T23:33:00.000-07:002009-03-29T23:38:39.997-07:00Mail stays in my Gmail inbox even after I trash it on iPhoneActually, on my 2nd generation iPod Touch, but its the same app as the iPhone. I had the most annoying problem: I followed all the Gmail instructions on setting up iPhone mail for gmail, yet when I would trash messages, they would remain in my inbox. After tons of research, I finally found <a href="http://discussions.apple.com/thread.jspa?threadID=1821454">an apple forums post</a> that resolved my issue.<br /><br />Basically, I needed to set gmail to expunge my message immediately on the 'Settings -> Forwarding and POP/IMAP' menu. It seems that gmail thinks expunging a message means removing it from the inbox. I thought that expunging a message meant deleting it, and I don't want my messages to be deleted. It would be very helpful if the gmail team would include a note about these settings in their instructions.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-46048791769356381852009-03-09T19:41:00.000-07:002009-03-09T20:27:34.448-07:00Crapple CareAlmost 2 years ago, I bought myself the nicest laptop possible for my birthday. I hadn't purchased any computer equipment for 5 years, and previously, I had constantly upgraded my desktop machines. I originally purchased a 17" Dell, but Vista had too many issues (mostly bluetooth), and Dell claimed my video card would have 256MB of RAM and I only got a 128MB card. I was tired of fighting Dell, and Apple had just released a new Macbook Pro with a 1920x1200 17" screen. I spent $3000 on the Macbook Pro and a 3 year AppleCare plan.<div><br /></div><div>Today, I took my Macbook Pro to the Apple store in the St. Louis Galleria because the sound died on me. Up until I got to the Apple store, Apple had an experience that far surpassed Dell. When my bluetooth didn't work with the mouse I purchased from Dell, I had to spend almost 4 hours on the phone before I could talk with a native-english-speaking high level technical support person. When my sound died on my Macbook Pro, I waited about 5 minutes to talk to a native-english-speaker. He seemed more knowledgeable than the Dell tier-1 tech support. He had me wait another 10 minutes while he asked higher-level technical support about my issue, and when he came back he scheduled me for an appointment at the Apple Store's genius bar for the same night. So far, so good.</div><div><br /></div><div>Once, I got to the Apple store, Apple began giving its lead in customer service back to Dell. I arrived 5 minutes early for my 8pm appointment and waited 20 minutes without explanation. If Apple is going to make appointments, they should at least explain when they are 15 minutes late. After a short diagnosis, they notified me that my audio board was probably dead and that it would need to be replaced, which was covered by my Apple Care plan. The Apple store clerk said it would take 1 week to replace the audio board. This is total crap. I could have almost purchased two Dell laptops for what I paid for my Macbook Pro, yet I have to wait almost 7 times as long to get my laptop back from Apple.</div><div><br /></div><div>When I was dealing with my bluetooth and video card issues with Dell, I had terrific repair experiences. Even though Dell had terrible phone technical support, their repair service is second to none. Dell sent an independent contractor to my office and she repaired swapped my bluetooth card the very next day after I called technical support. It took only two days for Dell to swap out my video card the first time, and only one day the second time. I never had to leave my office. The work was all done in front of me, and the repair technician was on time for all her appointments.</div><div><br /></div><div>Even though Apple makes a vastly superior product that I'm very happy to pay for, they have lost a repeat customer today. I'll probably buy Dells in the future and just dual-boot ubuntu.</div>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-47729790145593963752009-03-08T22:09:00.000-07:002009-03-09T20:27:48.367-07:00Windows UAC rootkitLast week, my mother-in-law had me look at her laptop because she couldn't defrag her disk, and "Google wasn't working". I thought perhaps her google problems were related to her satellite internet, and I didn't think defragging really mattered anymore, so I thought perhaps nothing was wrong.<br /><br />My gut was very wrong.<br /><br />I was able to get google results, so I assumed google worked. Additionallly, her gmail came up fine in firefox and in outlook. However, her defrag didn't work. The defrag UI would start, but it wouldn't perform a defrag or analysis, so I tried googling for a diagnosis of these symptoms.<br /><br />Then I discovered what my mother-in-law meant when she said "Google wasn't working."<br /><br />Whenever I clicked on a google search result in firefox, I was redirected to spam sites like couponmountain.com. When I tried to navigate directly to some security sites, or microsoft update my browser would fail to connect to the site.<br /><br />I noticed after initially clicking a google result, my status bar would show a link to windowsclick.com. I googled 'windowsclick.com' and found the following very helpful result:<br /><a href="http://www.antionline.com/showthread.php?t=278009">http://www.antionline.com/showthread.php?t=278009</a><br /><br />Unfortunately, my mother-in-law had gotten a rootkit somehow, and her AVG antivirus was unable to detect the rootkit, neither was spybot or adaware. Thankfully, the above link outlined a fix using combofix, malware removal software I'd never heard of, but it worked perfectly. I had to download the installer from another machine because the rootkit prevented me from connecting to the download site. After downloading, I changed the name of the executable so the rootkit wouldn't stop it from running. I followed all the recommendations of the combofix prompts and poof! no rootkit.<br /><br />Thanks combofix!Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-56992011882291603552009-02-01T20:43:00.000-08:002009-03-09T20:27:57.931-07:00Ubuntu 8.10 Intrepid Ibex on Dell Dimension 2400I just installed Ubuntu 8.10 Intrepid Ibex server on my Dell Dimension 2400. It was locking up after I would log in. I found the problem and workaround on Ubuntu's forums:<br />http://ubuntuforums.org/showthread.php?t=970037<br /><br />and here on Ubuntu's bug tracker:<br />https://bugs.launchpad.net/ubuntu/+bug/259385<br /><br />I applied the workaround and the login proceeded normally. Yay.Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-3249875402408778652009-01-12T13:57:00.000-08:002009-03-09T20:28:10.564-07:00dojo.require omitModuleCheck<a href="http://api.dojotoolkit.org/jsdoc/dojo/1.2/dojo.require">http://api.dojotoolkit.org/jsdoc/dojo/1.2/dojo.require</a><div><br /></div><div>I don't get why the omitModuleCheck option exists in dojo.require. I can't think of a situation where you would require a javascript library to be present yet not care whether loading of said library fails.</div><div><br /></div><div>Also, setting omitModuleCheck to true causes problems for debugAtAllCosts in firefox 3.</div>Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0tag:blogger.com,1999:blog-4861730248808553332.post-79079665238091110642008-10-07T18:10:00.001-07:002009-03-09T20:25:28.349-07:00I can tag in stackoverflow.comI have now massed 500 points and can tag questions in stackoverflow. Soon I'll have infinite power!Heathhttp://www.blogger.com/profile/16219966444108277892noreply@blogger.com0