Review: Nifty MiniDrive

IMG 9819

Having plenty of computer storage options available has always been important to me as an avid photographer and computer user. On the desktop thats easy to accomplish using both internal and external drives. But now that I've been using a laptop for work it's been harder to have more options for storage. External drives are a hassle, and additional internal drives are not an option on the next generation of Mac laptops.

I was really excited when I saw the Nifty MiniDrive on Kickstarter. The Nifty MiniDrive extends the onboard storage on a Mac laptop by utilizing the SD card slot to house a Micro SD card. This is a genius solution for elegantly adding a fair bit of flash storage to your laptop. I had always viewed the SD slot on laptops with skepticism because I use Compact Flash cards for my photography work. But this solution seemed like a great way to utilize that card slot while also giving me more options for storage.

The instructions for installing the drive on the Nifty website are very helpful. Installing the drive was straightforward. I did have to re-seat the Micro SD card once on my first installation to get it to seat correctly, but since there there's been no issues. The drive lines up very nicely on my laptop, as seen in the image above.

The Micro SD card I purchased for my MiniDrive is a Samsung 64GB drive. The other option I considered was a SanDisk 64GB drive. I typically use SanDisk drives for my photography work, but I decided to try out the Samsung because it was on sale and showed similar performance characteristics to the SanDisk. Straight read/write performance for the Samsung has been about what I would expect. Essentially it's similar to a USB 2.0 external drive for reads, and perhaps a bit slower for writes. Not all flash storage is created equal, and you're not going to set any speed records with SD cards like you might with USB 3.0 and Thunderbolt externals or newer SSD drives.


Screen Shot 2013 02 26 at 9 44 39 PM


The Nifty Team lists a few possible uses for the drive on their Kickstarter page. I decided to use my MiniDrive as a Time Machine backup for general documents, settings, and works in progress. The practical consideration behind this is that the largest currently available MicroSD card is 64GB - too small for backing up my entire startup drive. But the reality is that this is still large enough for what I need to back up. Source code is backed up by an SCM, and applications are easily replaceable. Photos I keep backed up using other methods, so any photos stored on my laptop are disposable.

After my initial tests, I set up the drive as my Time Machine backup volume. I configured Time Machine to exclude all of my apps, repositories, system data, caches, and any other large files that don't need to be backed up. That placed my total backup size in the 10-12GB range.

I use Time Machine as part of my Mac Pro's backup system too. I recently switched backup volumes on my Mac Pro and performed a 400GB initial backup of my startup drive. That backup took about 3 hours. I knew that an SD card is no where near as fast as an onboard SATA drive, but I was still expecting that the initial backup wouldn't take more than a few hours.

Screen Shot 2013 02 27 at 9 15 41 AM


In the end, the initial backup to the SD card took almost a full day to finish. I'm assuming that this is because of how many small files were included in the backup. The random small write speed of the SD card is not very fast compared to the large consecutive write speed that I was testing above. The screenshot of Activity Monitor above was while writing a single large file. Now, here's another screen shot while the backup was in progress. As you can see, the drive isn't maintaining a constant speed and so the backup ends up taking longer to finish.

Screen Shot 2013 02 26 at 9 46 56 PM

I finished the initial backup about two weeks ago, and I've been using the drive as my Time Machine volume ever since. The subsequent backups have finished much faster. I haven't noticed any performance issues while the backups are going on. Performance within the Time Machine is good as well with the MiniDrive. Scanning through file and folder versions for the past few weeks was fast and easy. I have not yet needed to recover a file from the ether of time yet, but backup isn't only about that. It's about the peace of mind you get by knowing that your data is safe. The Nifty MiniDrive gives me that, and in a stylish and elegant package to boot. In the end, that's what matters, and so I am very happy to have my Nifty MiniDrive.

Renaissance

IMG 3677

 

This week I had the pleasure of attending the inaugural Renaissance conference in San Francisco.  I decided to go because, like the rest of the people there, I make apps.

 

All of us know that there is a lot that goes into making an app.  First, there's the idea.  What is the job that your app will be hired to do?  Then there's design.  What will your app look like?  How will it work?  And then finally, there's code, the part that makes your app do what you want it to do.  The great thing about Renaissance is how it addressed everything that goes into making an app.  There are lots of excellent conferences like WWDC that intensely focus on teaching developers how to leverage the powerful frameworks that allow us to build amazing apps.  But this was the first conference I've been to that kept a higher level view that explained more of the what and the why than the how.  

 

The creative process is a big part of making an app.  Renaissance did a great job of setting the stage for a discussion around creativity with a talk by Brenda Chapman, the creator of Brave at Pixar.  Brenda's talk was great and was followed by an equally impressive talk by Phil Letourneau on Animating Your App To Life.  Animation is something that really enhances the experience in an app and Phil did a great job of explaining some lessons we can learn from Disney when it comes to designing the animations in our apps.  Mark Pospesel then explained some strategies that developers can use to make their animations seem more real.  The entire talk contained only a single line of code, but was extremely valuable for anyone trying to create engaging animations in their apps.

 

IMG 2694

 

Those talks really set the standard for the entire conference.  They were followed by great talks about the importance of type and copy, which is the true content of your application.  Bluetooth Low Energy was a high profile technology at Renaissance, featuring several talks and a half-day lab where attendees could try out some of the technology being worked on by the presenters and ask questions about building apps that take advantage of CoreBluetooth and integrate with BLE devices.  Not to be left out was Audio, which is one of the least often considered elements of a great app.  It was great to see several great presentations about that there as well.

 

The business side of making apps was well covered.  There were a nice variety of successful game developers (who shared some of their secrets for success), business leaders, and solo indie developers there at the conference giving presentations and talking to attendees.  Enterprise app development is a huge market and was well represented at the conference.  Members of the teams from Push.io and Parse gave great talks on supporting enterprise development through powerful backend services, and Brent Simmons shared some of his experience with NewsGator and Glassboard - his new enterprise collaboration iPhone app.

 

One of the recent trends in iOS app development has been a focus on quality.  I was happy to see a lot of developers talking about this at the conference, and happy to see several great talks about the topic.  One of the best points to come out of the first talk was that we should be testing to build better apps, not just testing to build bug free apps.  One way to do this is to automate the testing on your apps, and Jim Puls from Square gave a great talk about KIF - a framework designed to do just that.  I had the chance to talk to Jim a lot about KIF and I feel really good about using it as the basis for fully automated regression testing now.  I'm looking forward to writing more about that in the coming weeks.

 

One of my favorite quotes from Steve Jobs is "Design is how it works".  While developers still outnumbered designers at Renaissance, design was a major focus of the conference and almost the entire last day was devoted to it.  One of the most insightful talks was by Justin Maxwell on the concept of Path Dependence.  His point, if I can attempt to convey it, was that it isn't skeumorphism that people are against.  What frustrates users is when designers produce a UI that is divergent from what the expectations on the spectrum of experience and functionality are.  In the 90's, a UI for a sound mixer that matched a real life sound mixer made a lot of sense, because that's what users of the application would understand and expect since they were coming from a real-life sound mixer.  That expectation isn't the same for something like a podcasting app, where there is no real-life path dependence to influence a user's expectation.  His talk was fascinating and if the videos come out I definitely recommend checking it out.  Finally, the atmosphere at Renaissance was really good.  

 

I enjoyed the single track conference format, and I got to meet a lot of wonderful people before, during, and after the conference.  Everything about it was very worthwhile.  The venue was well chosen, in part because it gave the opportunity for exercise every morning, but also for being open and close to downtown San Francisco.  I would definitely recommend going to anyone considering it next year.  

 

Thank you very much to Tim Burks and Bill Dudney for organizing the conference, and to everyone else who came for making it a wonderful experience.

Blocks, Operations, and Retain Cycles

There's been some great discussions in the iOS community lately about the pitfalls of Objective-C and things to watch out for while developing iOS apps.  One of our projects at Mutual Mobile recently encountered a very difficult to diagnose issue that I wanted to describe so that hopefully others can avoid this happening to them.  The issue involved leaking images which resulted in a memory pressure warning and subsequent crash.  We knew what the symptoms were and how to reproduce it, but the root cause of the leak was extremely hard to pin down.  It used to be the case that most memory management issues were the result of programmer oversight.  But as you will see below, this issue would be extremely easy to overlook which is why I felt it was important to share a detailed explanation of it here.  
 
You can't start off a conversation about memory management anymore without mentioning Automatic Reference Counting (ARC).  Apple knew that managing memory is a big deal and that a lot of people in the iOS community were doing it wrong.  At WWDC in 2011, they mentioned that around 90% of the crashes on the app store were due to memory management issues.  ARC was their attempt to combat that.  Essentially ARC synthesizes calls to retain and release for you so that you the developer can focus on actually building your app.  It seemed too good to be true at the time, but I think I can safely say now that ARC has been a huge success.  It's now extremely easy for us to manage memory in Objective-C because, well, we really don't have to do anything.  As long as we follow the simple conventions the compiler takes care of the rest.  It really does work quite well.
 
There are a few gotchas with ARC though.  For starters, ARC doesn't really apply to C references (though it can help with converting from C to Objective-C, but that's another topic).  You do have to deal with C in iOS projects, because several libraries like CoreGraphics have a C interface.  Instead of method calls to retain and release, C libraries include retain and release functions, such as CGContextRelease(context c), to manage their memory.  ARC does not synthesize those for you, so you still have to call them.  CoreGraphics can be a tough framework to use, so my first thought was that the issue would be somewhere in this layer.  But it didn't take long to discover that this wasn't the case.  All it took was reading the code.  All of the calls to retain and release were balanced out correctly where the images were created.  Here's an example below taken from the method that we thought may have been at fault:
 
    CGContextRef context = CGBitmapContextCreate(NULL, target_w, target_h, 80, rgb, bmi);
    
    CGColorSpaceRelease(rgb);
    
    UIImage *pdfImage = nil;
    
    if (context != NULL) {
        CGContextDrawPDFPage(context, page);
        
        CGImageRef imageRef = CGBitmapContextCreateImage(context);
        CGContextRelease(context);
 
        pdfImage = [UIImage imageWithCGImage:imageRef scale:screenScale orientation:UIImageOrientationUp];
        CGImageRelease(imageRef);
    } else {
       CGContextRelease(context);
    }
 
So as you can see, at the top of the method the context is being created, so by convention it has a retain count of +1.  Then the context is used to draw an pdf into it, which is then copied out to an image so that it can be returned by the method.  The image ref also has a retain count of +1, because that's how the creation convention works.  It is then the developer's responsibility to release those references, which you can see is done in this example.  So far so good.  We knew from instruments that the image context was being leaked, but we still didn't know how or why.  But since we could tell both from our own inspection, and reading Apple's sample code for this exact use case, that it was being done correct, we went back to the drawing board.

The other main gotcha that remains with ARC is the retain cycle.  A retain cycle can take a few forms, but it typically means that object A retains object B, and object B retains object A, but nothing else retains object A or B.  They are still holding on to each other, so they never get dealloc'd, but nothing else is holding on to them so they both leak.  A lot of the time this can happen with a block, where the block retains the thing that created the block, and never gets released, so that the thing that created the block never gets released either.  That's clearly a problem.  It's also a problem that is tough to solve.  The static analyzer isn't well equipped to point these out to you, and Instruments isn't super effective at nailing them down either.  It will tell you something is leaking, but that's about it.  You do get a stack trace for the leak (or cycle if it detects one), but it's still up to you to pin down exactly what is causing the cycle.  You have to have a really strong understanding of how this stuff works and then do the detective work to parse through the code to find out what the cause could be.

In this case the team did understand retain cycles and did a lot to prevent them.  The view controller in question was responsible for showing all of the images that we are dealing with here.  That view controller creates dozens of blocks to perform image conversion operations from a PDF to an image.  The concern initially was that perhaps one of these blocks was holding onto the view controller, which holds the view hierarchy...and so maybe the view hierarchy isn't ever getting released.  There were indeed a few places where a block could have been "capturing" the view controller, and we took steps to prevent those.  Here's how you typically address that issue, by changing any reference to "self" to be a weak reference:

    __weak typeof(self) weakSelf = self;
    
    void (^ loadThumbnailBlock)(NSIndexPath *indexPath) = ^ (NSIndexPath *indexPath) {
        Page *page = [weakSelf.fetchedResultsController objectAtIndexPath:indexPath];
        [weakSelf loadThumbnailForPage:page forIndexPath:indexPath];
    };
    
So we eventually proved that the view controller was always being released, dealloc'd, and that all of it's views were going away.  Still the problem persisted, so that was still not the root cause.  The view controller was also handling the memory pressure warning correctly.  Whenever the app received the warning that it was using too much memory, it would remove the images it wasn't displaying from memory, as well as unload any views it wasn't using.  This was only a small fraction of the memory that had already been leaked though, so this only delayed the inevitable.
 
Finally, we nailed it down though.  We knew that the image contexts were being leaked both from checking instruments and because that's the only thing that could eat up that much memory.  The images are being rendered in blocks that are kicked off by the view controller.  We knew now that the view controller wasn't being held on to, because it was being dealloc'd, and so thus it also couldn't be holding onto the blocks that were rendering the images.  So something else must be holding onto those blocks...

Enter NSOperationQueue and NSBlockOperation.  NSOperationQueue and NSBlockOperation are built around Grand Central Dispatch to provide conveniences such as the ability to "cancel" an operation.  We were using this convenience to allow the app to cancel image conversion blocks if you closed the view controller before they finished.  Makes sense right?  Well, it was actually this optimization that was killing us in terms of memory leaks.  Take a look at the block of code below:

    __block NSBlockOperation *operation = [[NSBlockOperation allocinit];
    __weak typeof(self)weakSelf = self;
 
    MMVoidBlock thumbnailOperationBlock = ^ {
        if (!operation.isCancelled) {
            workerBlock();
        }
        
        [weakSelf.thumbnailOperationList removeObjectForKey:key];
    };
 
    [operation addExecutionBlock:thumbnailOperationBlock];

Notice any problems?  In this case we are building a thumbnail operation block that in turn calls a worker block.  The workerBlock() is actually what goes off and renders the PDF into a graphics context, converts that into an image, and saves the image.  But take a look at what else it's doing.  The block has a reference to the operation.  That sounds fine, until you look at the last line of that snippet.  The block, which holds a strong reference to the operation, is then being added to the same operation.  That addExecutionBlock method is going to retain the block, so now we have ourselves a retain cycle.  The block is holding onto the operation, so the operation won't be released.  But when the operation finishes the queue is going to release the operation, so now the operation has leaked because we don't have anything that holds a reference to it.  But the operation also has a reference to the block, so the block is never going to get released.  And finally, the block has a reference to the image and graphics contexts, which will now never be released either.  All because that silly block captured the operation it was added to.

Now the plot thickens even further.  The way you would typically solve this problem is by declaring the variable you want to use in the block as being weak by using the __weak specifier.  The example above inside the view controller illustrates that method.  But in this case, we can't do that because it will fail with ARC.  If you were to change __block operation to __weak operation in the example above, the operation would be released immediately.  So the performance optimizations of ARC bite us badly here too, because the operation will be nil in the last line of this function, which will cause the app to not work at all.  The compiler knows this and will actually warn you not to use __weak there.  In this case, what the compiler is telling you to do is actually the wrong thing to do, which is why this problem is so hard to solve.  By being a good sport and doing what the compiler tells you, you are lulled into a false sense of security that you will not have a retain cycle.
 
Here is the actual solution below.
 
    __block NSBlockOperation *operation = [[NSBlockOperation allocinit];
    __weak typeof(self)weakSelf = self;
    __weak typeof(operation)weakOp = operation;
 
    MMVoidBlock thumbnailOperationBlock = ^ {
        if (!weakOp.isCancelled) {
            workerBlock();
        }
        
        [weakSelf.thumbnailOperationList removeObjectForKey:key];
    };

    [operation addExecutionBlock:thumbnailOperationBlock];
 
What we had to do is just make the operation referenced by the block into a weak reference.  That way, the block isn't holding onto the operation, it just has a weak reference to it.  It's worth pointing out that pre-ARC, __block was sufficient to prevent a retain cycle.  But with ARC, __block no longer carries the same meaning and __weak must be used to prevent a retain cycle.  When the operation is finished and gets released by the operation queue, it will go away.  That will then release the block, which releases the image and graphics contexts just like we see it's supposed to in the sample above.  That resulted in dramatically improved memory performance and completely normal memory behavior.  Literally just that 2 line fix there.
 
It is worth pointing out that, in some ways, this represents a possible bug (or questionable behavior) on the part of NSBlockOperation.  What appears to be happening is that when you add an execution block, it retains it.  So far so good.  But when the block executes, it does not release the block, which would have actually broken the cycle.  Instead, the block won't be dropped until the operation is dealloc'd because, for whatever reason, NSBlockOperation does not release its associated execution blocks until dealloc gets called.  What the reason for that is, I do not know, but that's just the icing on the cake for what is already a tremendously ridiculous issue.
 
There is always a risk when dealing with scarce resources and expensive operations if you are not careful about how you use them.  Retain cycles are preventable, but it takes a lot of thought to consider how they may be caused by the code we write.  This situation represents a perfect storm in terms of memory issues on iOS.  It's easy for retain cycles to go unnoticed.  This one became so critical because we were leaking images, not strings and numbers.  Leaking images will cause an app to get killed due to memory pressure, where as strings and numbers probably never will.  Dealing with retain cycles can be extremely painful, and we should be especially careful to avoid them when dealing with expensive objects like Images and other graphical assets.  In this case, even with extreme care it was still nearly impossible to avoid a cycle.  This was a really tough problem to solve and I hope you all will remember it and avoid it in the future.

Calendaring on Mac and iOS

I am a fairly heavy user of calendars. This goes back to college when I worked part time jobs while keeping a full class load. But now in the professional world it's more important than ever to manage my calendar so that I can maintain my commitments to the people I work with, as well as maintain a sane work/live balance at home. Here's how I've set up my tools to manage calendars.

Mutual Mobile uses all of the Google services like Gmail and Google Calendar. While I don't use Gmail or Google Calendar for my primary personal email or calendaring service, I've been very impressed with both. Google Calendar in particular is an excellent service. The service is based on the CalDAV standard which is very widely used and supported. Apple's own Calendar apps on both iOS and Mac support Google Calendar as a backend data source, but not without some problems. I spent some time this past weekend identifying these limitations and configuring my setup to work around them.

The first problem is that Apple seems really to want all of your Calendar data to live in iCloud. Normally this would be fine. When I migrated from MobileMe to iCloud I was pleased to find that all of my old events were still there. My iCloud account actually has events dating back to 2002, where I added an event to watch The Lord of the Rings: The Two Towers. But here's where things go wrong. If you leave your "Default Calendar" set to iCloud, and leave the "Automatically retrieve CalDAV invitations from Mail" setting on, then Calendar will create a new set of all your events on your default iCloud calendar, even though those event invitations were sent from Google! This got to be really frustrating when I realized I had about 2 years worth of duplicate calendar information. Useful tip: if you use Google for calendaring, either set that as your default calendar or just disable this setting in general.

Screen Shot 2013 01 01 at 3 03 06 PM

Another issue is how alerts work in iOS. Google does have a push notification service feature for Google Calendar, which works really well. But that service isn't without it's flaws either. By default it also sends you an email reminder for all events. That obviously gets extremely annoying, so I turned that feature off, but it will also give you a browser pop up alert 10 minutes before a meeting. Pop ups are even more annoying than emails but you can't disable that without disabling notifications altogether. Notifications are a problem solved pretty elegantly on iOS, and in OS X Mountain Lion, so I really just wanted to get that working without all the email/pop up cruft. Well it turns out that is possible, if you set the default alerts setting on Mac and iOS for event reminders. This setting is off by default, where Apple strangely elects to leave responsibility for alerts to Google, but you can turn it on for individual accounts. I set mine to 5 minutes on iOS and 10 minutes on Mac. A word of warning though, this event reminder is added to the calendar event the first time the event is synced to your Mac or iOS device. If you're enabling this for the first time, you should remove your Google calendars from your Mac or iOS device, enable the setting, and then re-add them to make sure you'll get all of your alerts when you expect them.

Screen Shot 2013 01 01 at 3 08 46 PM

The last major issue is probably the biggest problem though. Unlike on the Mac, the Calendar app on iOS will not automatically update itself. This is a huge problem for a number of reasons. For one thing, people will add or change events on your calendar all the time during the day. If your calendar isn't being updated, you'll miss them all or go to the wrong place at the wrong time. The other main problem is that if you have alerts set up as I describe above, then if your calendar isn't up to date you won't get any alerts! This is because all of those alerts are device notifications, not push notifications. The event has to be on the device so that the app knows to give you a notification prior to the event start time. With the proliferation of push Email you would think we would have push calendaring by now, but sadly that hasn't happened yet. In order to keep your calendar up to date you'll have to resort to fetch.

Since I have all my email set to either Push or Manual Fetch, I was in a bit of a pickle here. My personal Email is iCloud, which uses push. For work email I use the new Gmail app, which also uses push, so I leave the iOS account setting as manual fetch. But when you change the iOS configuration for your Gmail account, you only get one choice. I didn't feel like having all of my email being fetched every 30 minutes, so I added a new account. iOS gives you the option to also add a CalDAV account directly, so I disabled calendars on my Gmail account on iOS and added a new account just for my calendar. That enabled me to leave my email configured to manual fetch, and calendars to fetch automatically every 30 minutes.

Photo

I've tested the performance a bit by leaving my phone unpowered over night with the setting enabled. My phone seemed to lose between 2-3% power idling for 8 hours at night, and my iPad lost about 2%. When you combine that with the other notifications and stuff that my devices get overnight, that seems like an acceptable loss of power to have an up to date calendar.

I'm hoping that doing this bit of house cleaning will also enable me to try out other great calendar apps like Agenda and Fantastical, which I have tried but never really used because my calendar information on iOS was never as reliable as I wanted it to be. That forced me to always rely on Google Calendar on the web, or the Mac Calendar app, to do my calendaring. Now I should be much more free to do the bulk of my calendaring on iOS, which I think is the way things should be.

Wildlife Photography

Woodpecker

I originally got into photography when I started camping. Visiting great state parks in Texas and venturing out into Canada, Colorado, and New Mexico was the perfect motivation to pick up a camera. But as I continued getting more into photography I became more and more interested in shooting sports. Like camping, I was very interested in sports and absolutely loved getting to shoot all kinds of events. I still love shooting sports, but it's not a regular part of my life, nor is it something that's very accessible. The wilderness, however, is very accessible to those who want to venture out, so I turned my photographic attention back towards the outdoors.

Shooting wildlife was really an accident for me. I went on a trip this summer to Colorado and decided to take my brand new Canon 300mm F4/L. I wasn't planning on doing a lot of wildlife photography, but I did want to experiment with the lens a bit. I knew it was good for flowers and compressed landscape scenes, and that it was very light (for a 300), so I brought it along.

Marmot 1

Along a few hikes I happened to run across some great wildlife. I saw several marmots and other small critters, and a few gorgeous birds. I hadn't planned to focus on wildlife but quickly that became my photographic focus on the trip. Much of the credit to that goes to the 300 F4/L (which I originally bought for sports). The lens is perfect for wildlife, by being both light enough to hand hold yet sharp enough to create stunning images of close up animals isolated with a gorgeous background blur. Just seeing a few of the images on the LCD was enough to get me hooked.

But there were a few other reasons why shooting wildlife was so appealing. For one thing, it's a lot like shooting sports. A large part of shooting sports is anticipation and fast reflexes. You have to understand the game and be able to predict what's going to happen, and then act instinctively by focusing on the right spot and quickly releasing the shutter. It's the same thing with shooting wildlife except that it's even harder to predict what animals are going to do, especially birds. There's no white lines that animals have to stay within, or goal to reach.

There's so much opportunity to experiment when photographing wildlife. You can try shooting at different angles to get different perspectives, or framing the scene differently to use a different background. You can get down low and shoot from ground-level for smaller animals, to see what things look like from their perspective, or hike up higher and shoot down on birds, to see what things look like from above. Like many types of photography, the background is very important when shooting wildlife. A lot of times an interesting background will really make a photograph more than an empty sky will.

Ruby Crowned Kinglet

Shooting wildlife is also the same kind of drug as shooting sports. Part of what makes shooting sports so addictive is waiting for the perfect shot. Photographers will often wait an entire game, or even an entire season, for that perfect shot of an outfielder diving to catch a ball, or a receiver diving across the goal line with the football. Capturing those images is rare but it's something everyone wants to do. Likewise, looking for that bird that you can hear in the trees and trying to catch an in-focus image of it in flight is just as addicting. But even without that goal, just being out in nature and enjoying the scenery is enough motivation to make wildlife photograph an outstanding pastime. The same way just watching a game makes shooting sports that much more enjoyable.

If you're interested in taking up wildlife photography, then treat it like any other hobby. Just start doing it. Like sports photography, wildlife is also fairly gear intensive, but before you invest thousands in equipment make sure it's something you enjoy doing. You can easily get by with any DSLR and a medium-long range zoom lens. Go out in the back yard and take some photos, then go out for a hike at a state park and take some more. You'll see birds, deer, squirrels, rabbits, etc. If you're up north maybe you'll see some elk, or even a bear. Remember to respect whatever wildlife you do see though. When you're in the wild you're in their home. Don't feed animals or do anything to antagonize them. Just watch, take pictures, and enjoy the experience of observing nature.