Lightroom's dual monitor support

I'm not sure how i went so long without having dual monitor support for editing photo's. This support was essentially non-existant in Aperture. Lightroom handles this in an awesome fashion.

You can run Lightroom on your primary monitor in either standard mode or fullscreen mode. Regardless of how you run it on your primary monitor, you can output the photo's to a secondary monitor for previewing. In the following photo, you can see that I am in Grid view on my primary monitor. In this view, I can rate and add my keywords. I can move between photo's on my primary monitor and view the fullsize photo on my laptop's screen.

This feature works great can be accessed from the dual monitor icon on the bottom left of the screen.

Options for 2nd monitor

The more I use Lightroom, and get used to the different interface, the more I like it and find myself surprised at how long I put up with Apertures lack-luster feature set (relative to Lightrooms).

Wireless, Cross-device, photo syncing in 2014

For the last two years I have used Aperture for storing, organizing and sharing our photos. It wasn't the perfect photo solution, which I've blogged about more than once, when it came to wirelessly getting photos from several devices in to the Aperture library. I did however like how much flexibility it provided me for organization. I know that Lightroom had really good organizational features, but it didn't play well with my iOS devices and Photostream wasn't supported, which made wirelessly uploading my photo's impossible at the time.

The stars have since aligned, with Aperture being discontinued and Adobe releasing Lightroom for iOS, I now have the opportunity to move over to Lightroom and actually end up with a much better solution. After getting all settled in with Lightroom, I am now able to take a picture on my iPhone, open Lightroom on my iPad and make edits, then open up Lightroom on my Mac or Windows PC and have the original photo and it's edits already ready for me to add keywords to and organize. Even better yet, is that my wife's iPhone has Lightroom on it, and every picture she takes, shows up on both of my iOS devices and on our two computers, without any issues. Well worth the $10 a month it's costing, plus I get Photoshop for my machines and iOS devices, so it's a great value for the price.

The setup

I downloaded and installed Lightroom mobile on my iPhone and my two iPads. Then I downloaded and installed Lightroom mobile on my wife's iPhone and her iPad. Finally, I downloaded Lightroom for my Windows machine and my Mac (technically the same machine, just dual booted). Next, I created a collection on my iOS devices, one collection per device. When you create a new collection on a device, you can tell it to auto-import your camera roll. It will automatically upload your photo's to the Lightroom cloud, and sync them to all of your devices, in the background.

Once each of our devices has a collection created, and has the auto-import enabled, we see all of the collections on all of our devices. This allows us to take a picture on any device, and not have to deal with sending to photostream or AirDropping a large number of files. Our photo's just show up on all our devices. If you want, you could create a single collection, and assign it to auto-import on all devices, so all of your photo's go into 1 collection from all devices. We chose to create one collection per device though so we could make finding a photo easier. I know my wife snapped a photo of my daughter on her iPad, so I just go to her iPad collection from my phone and find it.

Here, you can see all of our collections easily accessible on my iPad.

Now that all of our mobile devices were set up with Lightroom, I launched Lightroom on my Mac and discovered that the collections were available there without any set up. Now I can easily select the photo's and import them in to my library, add keywords, edit them and back them up.

One of the other cool features of Lightroom is that I can select any photo from my library, add them to a collection and enable mobile sync on the collection. Now any photo I add to the custom collection will sync to all of our mobile devices. Extremely easy.

Differences

You can technically sync photo's to iOS from Aperture and iPhoto as well, using Photostream. The difference between Photostream and Lightroom Collections is that Photostream still syncs down the photo to your device (albeit a small version), while Lightroom only syncs a thumbnail. Since majority of the time, users won't actually open all 500 photo's to view on their device, you only need 500 thumbnails. As you can see from my photo above, I have 142 photo's from my wife's iPhone, but it's only using 31mb of storage. When you open a photo to view the full photo, Lightroom downloads the full-resolution for you to see. Much better!

With Aperture/iOS, I could share photo's with my wife through Photostream as well, but my wife would end up saving the photo to her camera roll and a duplicate ultimately ended up in my Aperture library. I would spend a lot of time removing duplicates. Luckily, it seems that Lightroom is smart enough to not import duplicates. Another benefit is that I don't have to manually upload 20 photo's that I just took of my daughter to Photostream for her to see. They just show up in our Lightroom.

If I wanted to have a photostream per device, it made things even more complex. Take a picture on my iPhone, and upload to photostream, then take a picture on my iPad 5 minutes later and manually upload to photostream again. With Lightroom, we can take pictures on any device at any time and not deal with uploading. Lightroom handles it all for us with less effort.

Tags & Keywords

Lightroom calls their version of Tags, Keywords. I downloaded an app on my iPad called Photosmith, that lets you create a collection of photos on your Mac (or Windows) and sync the collection of photo's to your iPad. You can then add keywords, edit the photo's, name them and then sync the changes back to Lightroom. It's a great way to 'tag' photo's while on the go. Until the Lightroom Mobile apps support keywording, I'll use Photosmith to do all my keywording while on the go. It's a bit difficult to set up initially, but in the end it works pretty well.

This process is by far the best photo syncing solution I've found, after several years of messing with trying to take care of syncing to the computers wirelessly and sharing across all devices.

Using NDepend to analyze Mud Designer Alpha

Why analyze?

Since the latest build of the Mud Designer re-write isn't ready to ship yet, I thought I'd go back and run a code analyizer against the original Mud Designer Alpha, so that I can compare the quality of the old engine to the new (once it is ready). The goal of the re-write was to improve the code base and make it more abstract and not as tightly coupled.

I was provided a copy of the NDepend toolchain and used it to run the first report against the Alpha version of the Mud Designer and thought I'd share the results of it.

The stats

After the analysis was completed, it provided me with some basic stats.

  1. The project contained 3,852 lines of code, of which 47% was commented. Pretty good coverage, almost to much. Half of my code base shouldn't be covered in comments if the code was wrote clearly. The project
  2. The project contained 152 Types across 5 assemblies with 1,091 methods.
  3. I did not have any rules with errors, but ended up with 61 rule violations in total. I'm not sure if that is a significant number for the number of lines/methods/types the project has or if it is minor.

The violations

I had two violations for Types being to large and one for a method that was to complex. These two violations were anticipated before hand, since all three of them take place in the WinForms code-behind. Code-behind on a WinForms project tend to be ugly and cumbersome, so this was expected. It's also a large part of why I chose to build the next version in WPF with the MVVM pattern.

The report also told me that I had a total of 8 methods that needed to be refactored. With 4 of them being engine methods and 4 of them being WinForms project methods. Once again, the amount of code in violation within the engine was minor next to the WinForm project. The WinForm project just over double the number of IL instructions (117 vs 242) than the rest of the engine.

Something that I had not expected was that I had 9 Types with to many methods. With all but one of those Types living within the Engine assemblies. The bulk of the bloated Types lived under the GameObjects namespace, which was responsible for all of the player, item, world and npc code. Reviewing the code and the analysis showed that the objects could really use a good refactor. Something that I was already planning on the next version of the application. The BaseMob Type contained 81 methods by itself. It made me cringe and not want to even go back and look at the source.

I'm not going to go over every rule violation that took place in this report with this post, but there are a few interesting things to point out.

The report showed that I had a problem with cohesive methods, potential issues due to invoking virtual members within my constructors and that I was not properly disposing of Types that implemented the IDisposable interface. I'm really anxious to get the dust to settle on the new version of the Mud Engine source so that I can run the tool against it. I am planning on a series of posts as I build out the new engine and run the analysis tool against it. The goal of the series would be to demonstrate rule violations and how to address and fix them.

There's really no question that using NDepend will help make my code base much better. It is fairly complex at first when you go to use it, but their documentation seems pretty good. Using their documentation with the analysis and a bit of googling, you can quickly pick up what patterns can be applied through-out your app. It's really nice.

Stay tuned for additional posts coming soon.

ValidatableBase: Back to the drawing board

A couple of weeks ago I posted about my new ValidatableBase object I put on GitHub. It worked pretty good for Windows Universal Apps and I'm enjoying it's simplicity.

I ran in to some drawbacks when using it with WPF however. In WPF, most projects use either IDataErrorInfo or INotifyDataErrorInfo. Neither of these two interfaces worked for the business requirements I have. Neither interface make it really easy to break up your validation errors in to categories. What if want to perform validation and have it come back with a warning instead of an error? You can't do that with IDataErrorInfo and while you can do it using INotifyDataErrorInfo, it requires a decent chunk of plumbing to expose and doesn't make sense semantically. To get all errors, warnings and information messages, you access the GetErrors method or HasErrors property. It makes things confusing when building a framework and you want others to access warnings and informative messages from the model. "Just grab the warnings from the GetErrors method". Huh?

So I thought I'd just move over and ValidatableBase in WPF. The problem that I ran in to with it is that it was not easy to quickly re-evaluate a properties failed validation. I can of course re-run the entire validation process, but I wanted to have more control. Since the Func< > required by the ValidateProperty is typically an anonymous method or a private method within the model, it makes invoking the ValidateProperty method on the model really unsafe. The view model was reproduce the validation rules for the property, which it shouldn't ever do. If I exposed all of the individual validation methods within the model, then I kind of feel like I'd be breaking the Open/Closed principle.

To resolve this, I set out to re-build the ValidatableBase with a better version (still a work-in-progress). The revision will provide support for two methods. ValidateAll() and ValidateProperty(string property). These two methods wil then hit a cache of Validation Rules that each object has associated to it's properties and run the validation from those objects. As an example, I can create a StringIsNotNull validation rule object and add it via a property. When a model is instanced, it wil find all of the validation rules required and cache them. When either of the aforementioned validation methods are invoked, the applicable validation rules will get their Validate() method called and your property will be validated. If you want to re-evaluate a property, you can with ValidateProperty("Email");. This lets you abstract the actual validation rules out in to independent objects that can be re-used across your models.

The work is mostly done, but I'm having to spend some time determining the best way to provide parameters to the validation rules. Once this is ironed out, I should be able to publish a new version to GitHub.