Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Sunday, August 24, 2014

RequireJS Impressions

RequireJS is a JavaScript library for defining and loading modules. It provides an alternative to including multiple <script> tags in your HTML in the right order and defining countless global variables (or properties for global variables.)

I've been using it quite a bit lately, so I have some opinions about it.

Good News

I like that RequireJS works with many browsers. The official site claims compatibility with ancient versions of every major browser. And have you seen its source code? A piece at the top checks to see if it's running on the Playstation 3's browser and does a little workaround just for it. I get the impression that RequireJS will work on anything that one would need it to, and that's a very good thing when you're building web sites that need to work everywhere.

"Ehhh..." News

Module names are case-sensitive. If you get the case wrong, RequireJS will happily reload modules. If those reloaded modules do anything to global state, you're heading for headache.

I could find only one bundling tool that properly bundles RequireJS modules together: the optimizer (r.js) that comes with RequireJS. This tool has "experimental support for source maps" (source: RequireJS Docs - Source Maps), so not using source maps poses two problems:
  1. Serving individual files for development and optimized files for production
  2. Actually using those files in each environment
Solving both of these problems can get tricky, especially in the ASP .NET MVC 4 environment that I've been working with. The easier of the two problems is the first: force the asset pipeline to use the output of r.js instead of its own optimized output. Easier said than done, but it's not impossible.

The second problem, actually using the files, is difficult and gets interesting when you're to use the application cache. One solution that I came up with is absolutely terrible and I will not be sharing it because it's wrong in so many ways. But I came up with it because there isn't much documentation available for taking full advantage of RequireJS's optimizer. Currently, it's a few sparse details and a (non-working) configuration file they put up on GitHub. This documentation could use some serious improvement.

These warts, while major, won't stop me from using RequireJS. It provides worthwhile functionality to client-side JavaScript. Browserify seems like a worthwhile replacement that fixes many of my RequireJS gripes, but I haven't used it yet and its compatibility is not as good as RequireJS's.

Sunday, June 29, 2014

Using Git With TFS

Background (In a hurry? Skip this part.)

Did you know that Android Studio, as of this writing, does not have Team Foundation Server integration? This has a wide variety of consequences:
  • Every project file is read-only, and you need to unlock each manually
  • You cannot checkin files from Android Studio
  • New files are not automatically added to source control
  • Files that need to be excluded from source control might get checked-in
One way to avoid these problems is to use a different source control for Android Studio projects until it supports TFS. But you may be required to use TFS for any number of different reasons. For example, I work for a company that uses TFS for source control and work items.

There's a way to use Git (which Android Studio fully supports) with TFS repositories.

Use Git-TF

Git-TF allows you to use Git to manipulate TFS repositories. This is great for situations where you're not working from an IDE with TFS integration but still need to use TFS.

There are two ways of installing Git-TF: manually and with Chocolatey. Both are easy, but be careful about using the Chocolatey install because it requires JRE 7 (and not 8) and overwrites some system settings that you may need.

You'll want to follow Git-TF's "Individual developer with a new repository" instructions because you will want to work with a new Git repository on your local machine.

Recommendation: Checkin .gitignore to TFS

TFS does not use .gitignore files, but I think that they should still be checked into TFS. Multiple members of your team may want to use Git-TF for a project, and including .gitignore makes it easy for them to jump-in without having to add their own .gitignore.

Be Careful About Directories

If you currently use Git and TFS, using Git-TF should be easy. But there's a catch that I've encountered: Git-TF does not work well when used within a directory mapped to TFS.

If the TFS repository root is mapped to C:\TFS, and your Git repository is in C:\TFS\AndroidStudioProject, you will encounter errors when trying to checkin or shelve changes. These errors are workspace-related and (as far as I know) can only be resolved by unmapping the directory or creating your Git repository in a different directory (such as C:\GitProjects).

Wednesday, January 15, 2014

Sinatra Caches Templates

Yesterday, I learned the hard way that Sinatra caches templates when running under a non-development environment by default.

How I Found Out

My company site (Leavins-Software.com) was having serious issues where changes in layouts were not reflected in web browsers. I originally thought that this was a bug in how I set the Last-Modified HTTP header. Then I looked closely at Firefox's web console (specifically, the 'Network' tab). Last-Modified was being set properly!

I started making template changes in production to see what the real cause was. Please don't try this at home. I only did it because I'm a cheapskate working on a low-traffic site.

The test page seemed to update with every other change (which is odd behavior). Last-Modified was being updated properly, but the page wasn't changing. And then I got lucky: I was served an old version of the site with a properly-set Last-Modified date! Then a question hit me: "does Sinatra cache templates?"

Yes, Sinatra caches templates. Just not under the default development environment.

How Sinatra Caches Templates

Sinatra uses Tilt to render templates. While digging around Sinatra's source code, I discovered that Sinatra also uses Tilt's built-in caching for rendered templates. Tilt uses a Ruby Hash object for caching, meaning that Tilt's cache is per-instance.

This is different from how Rails does this. I'm not a Rails expert (I should probably change this if I want to continue working with Ruby), but I know that it uses a variety of different caching methods including page caching, and, to quote Caching with Rails, "Page caches are always stored on disk."

Each Sinatra app instance has its own cache, and I managed to hit the instance with a previously cached version of the template.

There is a Sinatra app setting named 'reload_templates' that controls caching behavior. The default setting is "true" for development and "false" for everywhere else. This is why Sinatra doesn't cache templates by default for the development environment.

Fixing Related Issues

The easiest way to resolve a template update issue is to just restart the Ruby app server. Really!

WiX & MSBuild - Adding WixExtension To Fix LGHT0094

I recently ran into a problem with compiling a WiX project using MSBuild. Here's the error message:

error LGHT0094: Unresolved reference to symbol 'WixUI:WixUI_Minimal' in section 'Product:*'. [C:\Dir\Test.wixproj]


To fix this specific error, the MSBuild file needs the following element (as a child of the Project element):

<ItemGroup>
    <WixExtension Include='WixUIExtension' />
</ItemGroup>

Adding this element causes the WiX 'candle' build step to include the extension that you need. You need to change the Include value if you require a different extension.

If you receive this error when building a WiX project using Visual Studio or the 'light' command-line tool, follow the Using Built-in WixUI Dialog Sets tutorial included in the official WiX documentation.

(tested with WiX v3.8)

WiX - CNDL0107 "invalid child element" in Product

When building a WiX file (tested with v3.8), you might see an error message similar to this one:


error CNDL0107: Schema validation failed with the following error at line 1, column 396: The element
'Product' in namespace 'http://schemas.microsoft.com/wix/2006/wi' has invalid child element 'UIRef' in namespace 'http://schemas.microsoft.com/wix/2006/wi'. List of possible elements expected: 'Package'. [C:\Dir\Test.wixproj]


This error might seem cryptic, but indicates that the schema expects Package to appear as the first element of the Product element.

Thankfully, there is a very easy fix for this error. The UIRef element (or whatever child element comes first in the WiX file) needs to be moved below the Package element.

Tuesday, December 3, 2013

Adding Code Just for Debug Build with C#

It's very easy to add code that will only run for Debug builds for C# projects. The if directive is all you really need to know to do this.

Just add the following two lines to your source file:

#if DEBUG
#endif

You put the code that you want for the Debug build between those two lines. When you compile the project using the 'Debug' build configuration, the compiler will include the code between those two lines. Otherwise, they are ignored.

What if you want to include code for anything other than the Debug build? Just swap 'if DEBUG' for 'if !DEBUG' in the first line of code.

Troubleshooting

The reason why this works is that, by default, the Debug build configuration of a C# project defines the 'DEBUG' constant. If your debug-only code doesn't run when using a debug build, the problem might be in your build settings.

In Visual Studio:
  • Right-click the project that you're working on
  • Click 'Properties'
  • Click on the 'Build' tab
  • Make sure that the build configuration is set to Debug (using the dropdown menu that should be at the top of the build settings pane)
  • Make sure that 'Define DEBUG constant' is checked 
  • Save (Ctrl + S)

Making Your Own Special Build

Because this behavior only relies on C#'s #if directive and a preset DEBUG constant, you can easily use this to add code for any special build of your project. A good example of this is a 'Demo' build configuration. If you setup a Demo configuration for your commercial application, you can sprinkle #if directives statements throughout your code and get demo-specific (or retail-specific) functionality in your program.

The following how-to was written using Visual Studio 2013, but I think that it will work just fine if you're using VS 2008 or later.

1. Add Solution Build Configuration

This can be done through the Build > Configuration Manager... window. Click the 'Active solution configuration' then click '<New...>'. Give it a name like 'Demo'. You should probably copy settings from the Release build. Make sure that 'Create new project configurations' is unchecked unless you want to add one for each project. Click OK, but don't close the 'Configuration Manager' window.

2. Add Project Build Configuration

Look at the 'Project contexts' grid/spreadsheet. Click on the 'Configuration' cell for your project. Click '<New...>'. Give it the same name as your solution config, copy the Release build settings, and uncheck 'Create new solution configurations'. Click OK, but don't close the 'Configuration Manager' window.

3. Use the new project build configuration

Make sure that the 'Active solution configuration' is your new config (Demo).  Click on the 'Configuration' cell for your project and select your new project config. Close Configuration Manager.


4. Add the conditional compilation symbol

  • Right-click the project that you're working on
  • Click 'Properties'
  • Click on the 'Build' tab
  • Make sure that the build configuration is set to your new config (using the dropdown menu that should be at the top of the build settings pane) 
  • Type your new compilation symbol in the 'Conditional compilation symbols' text box
  • Save (Ctrl + S)
 

5. Use your new compilation symbol in code

If you're using 'DEMO' as the compilation symbol, sprinkle these two lines throughout your code to write build-specific code.

#if DEMO
#endif

Friday, November 15, 2013

Getting Started with KSMVVM.WPF Part 2: Messaging

(This is part 2 of 2 in a series about getting started with KSMVVM.WPF)

At the end of Getting Started with KSMVVM.WPF, we successfully converted our SampleApplication to use ViewModels. However, one of our ViewModels still has UI-specific code in it. If we write and run automated ViewModel tests, testing FormViewModel.Submit will show a MessageBox. This is not good!

KSMVVM.WPF has a messaging component, and we'll use its BasicMessager class to move the call to MessageBox.Show out of FormViewModel.

Thursday, November 14, 2013

Getting Started with KSMVVM.WPF

KSMVVM.WPF is a 'kinda small' Model-View-ViewModel framework for Windows Presentation Foundation (WPF) that I released earlier in 2013. It's a little different than other micro-MVVM frameworks because it was specifically designed for migrating existing code-behind WPF applications to MVVM.

Some nice features of KSMVVM.WPF include:
  • Functionality to allow ViewModels to control program navigation (in a manner to allow for automated tests)
  • Lightweight, easy-to-use string-based messaging
  • Two ICommand implementations; a 'hack' one for existing apps, and a 'non-hack' one for new apps
This 'getting started' guide will illustrate use of KSMVVM.WPF in an existing WPF application. This guide assumes that you are using a recent version of Visual Studio (or VS Express) with built-in NuGet functionality. I'm actually using VS Express for Desktop 2013 RC for this tutorial.

The tutorial continues after the page break.

Thursday, September 12, 2013

Skippable - Skip UI-specific Code During .NET VM tests

KSMVVM.WPF, my "kinda small" MVVM framework for WPF, used to have a class named Skippable. Its purpose was simple: to allow the inclusion of UI-specific code inside of a View Model and have it be skippable for unit tests.



How to Use Skippable

Call Skippable.Do(func) in your View Model code and place UI-specific code in func.

Wrap your View Model unit test code in a using(Skippable.Skip) block.

Why Was It Removed?

Before I added a messaging class to KSMMVM.WPF, Skippable was the only built-in way of triggering a change in the UI that could not be prompted through binding alone. For example, calls MessageBox.Show() were intended to go inside of a Skippable() block until the program transitioned to a MVVM framework with messaging capability.

I realized that Skippable encouraged poor programming practices. MVVM is all about separation of concerns, and Skippable violates that separation by allowing 'View code' in the View Model. It also requires tests to know if something uses Skippable.

Skippable was meant to help programmers transition WPF code from code-behind to a proper MVVM framework, but it did a grave disservice to developers who 'stick' with KSMVVM.WPF.

Friday, August 23, 2013

Using AngularJS with Bootstrap Form Validation

If you are using AngularJS with Bootstrap (formerly Twitter Bootstrap), you will want to use AngularJS's form validation with Bootstrap's form classes. This can be surprisingly tricky and requires careful use of AngularJS's ngClass directive.

This is best illustrated with sample markup. It's extracted from a project that I'm working on:


The general idea behind this is that you need to set Bootstrap's 'has-error' class when loginForm's email field is invalid. Simple enough, right?

AngularJS introduces two issues that are present in the latest unstable version (1.2.0rc1). They could be in previous versions, but I didn't check.
  1. You must have quote marks around the name of the 'has-error' class in the ng-class expression.
  2. The input must be bound to the model by using AngularJS's ngModel directive
If you just put ng-class='{has-error: loginForm.email.$invalid}' your JS will crash within AngularJS because it's an invalid expression.

I have little idea why data binding is required. I suspect that AngularJS requires it because it expects you to use the field's contents somewhere else in your app.

Wednesday, July 31, 2013

Changing Control Visibility in WPF MVVM Apps

In WPF MVVM applications, you might need to show, hide, or collapse controls based on data from ViewModels. This is trivial for code-behind applications: name the control & manipulate its visibility directly when you need to. MVVM applications need a different approach. In this post, I'll outline two of the approaches that I have used.

If you use a different approach for manipulating Visibility in WPF MVVM apps, let me know!

Approach A - Introduce Visibility Properties to ViewModel

First, add a new property to your ViewModel. The type of this property needs to be System.Windows.Visibility. The setter for this property can be private; the view only needs the property's getter.

Second, bind the new property to the control's Visibility property.

The advantage to this approach is that you don't have to touch your View's code-behind. The disadvantage is that your ViewModel now contains presentation logic, which is bad for separation of concerns.

Approach B - Set Visibility in Code-Behind

Using this approach requires setting x:Name for your control. The idea is that you add code to code-behind that uses ViewModel values to determine the control's visibility.

If visibility does not change during the Page's lifetime, you can go ahead and set Visibility during Page initialization using ViewModel data.

If the visibility of your control can change during the lifetime of the page, you'll need to use messaging or events in your ViewModel to trigger updates to the page. The event handling (or message handling) code will set the Visibility of the control.

The code-behind will be larger (due to the Visibility-setting code and any additional event/message handlers that you add) and your Page will have an additional property (the control), but this allows you to manipulate control visibility without adding presentation-specific code to your ViewModel.

Sunday, May 19, 2013

.NET Debugging Tips

In my three years of professional coding experience, I have fixed many problems in .NET programs and unit tests. One example of this is a WPF problem that ultimately involved a faulty GetHashCode() implementation. Most of the problems that I have faced involve NullReferenceExceptions, off-by-one errors, bad regular expressions, and "normal" stuff like that. I've fixed some major concurrency-related issues and even a bug that took 13 steps to re-produce. I don't have a decade of experience, but I know a thing or two about debugging .NET code.

(I) Don't Rely on Breakpoints

Visual Studio has excellent support for breakpoints, but I rarely use them. Removing a breakpoint can be a time-consuming process if you want to leave other breakpoints enabled. They also stop the program entirely, and I've seen cases where breakpoints prevent concurrency issues from being re-produced.

I use breakpoints only when I need to look at local variables in a buggy piece of code. Otherwise, I just sprinkle Debug.WriteLine statements when needed. I can act on Debug info faster than I can a breakpoint, and the program doesn't stop for seconds while printing debug statements.

There is one major disadvantage to using Debug.WriteLine: you have to alter source code to use it. Please do not commit code with Debug statements that you don't plan to keep. Every version control system that I know of has a diff support, and you should check these diffs when you commit code.

(I) Have Plenty of Unit & Integration Tests

I am a big proponent of unit & integration testing. I feel that good tests help developers figure out what isn't causing a problem before they start. Automated testing is not the end-all, be-all of bug prevention. You'll miss edge cases, and there's no way (that I know of) to detect weird GUI-related issues before you stumble upon them. Tests are merely good tools.

If you are able to, I highly recommend writing integration tests. In past endeavors, I had to mock everything out to such an extent that real-world issues (like a missing table, column, or bad parameters) would not be detected until the manual testing phase. My software uses SQLite, and I write tests that write data to real SQLite database. These integration tests helped me write persistence code that didn't easily break.

While debugging, I try to write unit & integration tests that cover the bug. This helps me debug the problem and ensures that the exact same problem does not return in future code revisions.

Rules of Thumb

Common NullReferenceException causes

When my code throws a  NullReferenceException, it's usually one of two things:
  1. I forgot to check a parameter or property for null
  2. Type cast returns null (and I forgot to check for null)

Silently handling exceptions is bad

Silently handling exceptions silence major problems with your code. It also makes your code harder to debug. I highly recommend not writing error-handling code that does nothing.

Of course, I've written error-handling code that basically does nothing. The hack was very well documented to indicate why I was silently handling exceptions, and I didn't catch Exception. That's bad because StackOverflowException and OutOfMemoryException exist.
 
On a related note, catching an exception and throwing a new one can hide the true source of the exception.

 It's probably your regular expression

If a regular expression can be the cause of a problem, it probably is! This isn't a knock against regular expressions, as they can be very useful for validating certain types of input. It's just tough to write one that works all of the time for all cases.

Thursday, May 16, 2013

Identifying WPF BackStack Entries

Frame.BackStack is a useful property in WPF applications: it's an IEnumerable for a frame's navigation history. In my experience, these back entries tend to be JournalEntry instances. JournalEntry.Name can help you find what Page is represented by the JournalEntry, but it is a little tricky to use in practice. Name can be one of four things:
  1. The attached Name attribute.
  2. Title.
  3. WindowTitle and the uniform resource identifier (URI) for the current page
  4. The uniform resource identifier (URI) for the current page.
(Source: JournalEntry.Name documentation on MSDN)

If you set x:Name for a page, the corresponding JournalEntry.Name will be that x:Name. Doing this allows you to (somewhat) reliably identify the JournalEntry's page.

Saturday, May 11, 2013

Freezing jQuery NuGet Package Version

jQuery v2.0.0 was released last month, and it does not support Internet Explorer 6/7/8. If you use NuGet to include jQuery in your .NET projects, your jQuery files might be updated to this latest version without old IE compatibility. You can force NuGet to keep v1.9.1 when you update your solution's packages, but you have to manually edit the package file for each project with jQuery.

A project's packages.config file can be found in the root directory of that project (where the .proj file is). Open each packages.config file and look for a line similar to this one:


<package id="jQuery"
            version="1.9.1" 
            targetFramework="net40" />

(The targetFramework attribute may be different)

Adding an allowedVersions attribute allows you to control what version will be used by NuGet during updates. Here's an example:

<package id="jQuery"
            version="1.9.1"
            allowedVersions="[1,2)"
            targetFramework="net40" />
allowedVersions="[1,2)" tells NuGet to grab the newest version that falls between v1.0 and v2.0 (excluding v2). This will likely be v1.9.1, the most current version before v2.0.0.

For more information on NuGet versioning, please go to NuGet versioning documentation.

Sunday, April 14, 2013

Setting Up Redmine for Solo Developers

Developers often have many projects going on at the same time. If you're a developer, keeping everything organized can be tough. It's hard enough when you are part of a software development team (who hopefully has a dedicated project management system already). Project management can become exceptionally tricky for solo developers.

Solo developers have to do everything in a project. In my personal experience, having that massive amount of responsibility is often overwhelming. I used to keep TODOs in a text file (and used a whiteboard for daily tasks), but my TODO file became so large that I had to split it. Splitting the file just made me more confused about what I needed to do.

How did I solve this? I started using Redmine.

Redmine for Solo Developers

Redmine is a web-based project management system. It uses Ruby on Rails, and I have experience with deploying Ruby apps, so Redmine is a natural choice for me. The official Redmine installation guide covers much of what you need to know to setup Redmine. Here's a quick guide to how I installed Redmine on a local server (a Mac Mini that I have previously talked about):
  1. Create a new user and install rbenv (you could also use RVM) to that user's home directory
  2. Follow the official Redmine installation guide.
    1. Make sure that you install SQLite; managing a file is easier than managing a SQL server
    2. During the "Database connection configuration" step, specify a SQLite database file for the production server
    3. You may run into some trouble running migrations: these errors are easily corrected & solutions are out there (usually, searching for the error message works)
  3. Make sure that the server runs using WEBrick
  4. Setup & run Thin (or any other Ruby server)
    1. This is partially discussed in the official install guide under "Additional dependencies"
This setup will give you a project management system that will work well, provided that you are the only one using it. You should look into using different technology (especially for the SQL server) if you are setting-up Redmine for a team.


Sunday, April 7, 2013

Advice to New Programmers

Here's some advice that I could have used back when I started programming in 2006.

Learn a Revision Control System

Programmers make mistakes. Not using a revision control system can make these mistakes costly. Have you ever deleted a file that you needed or completely messed-up a file by adding too many features at once? Then you know that reversing them can be a time-intensive process.

Revision control systems (also called 'source control systems' and 'version control systems') are essential to serious software development. When used properly, revision control allows you to easily reverse mistakes that you (or others) make.

There are many revision control systems out there, and here are some of the best-known:
  • Git
  • Mercurial
  • Bazaar
  • Team Foundation Server (TFS) 
  • Subversion
I recommend starting with Mercurial, Git, or Bazaar due to ease of setup and ease of use.

Your First Language Doesn't Matter

When I first started, I (sort-of) feared that having Visual Basic .NET as a first language would limit me in terms of what I could do as a software developer. This fear was completely unfounded, and I went-on to write tons of code in other languages.

Much of the fundamentals of programming can be learned from any well-known language. When you're just starting out, don't worry about what language you are using.

Try to Learn Multiple Languages

After you've learned the basics of your first language, I highly recommend learning other languages because it is a good way to expose yourself to different programming techniques and concepts. Learning multiple languages also reinforces your knowledge of fundamental concepts common to any language.

Here's the hard part about this advice: I can't tell you what programming languages you should look at. You'll have to discover them on your own and look into anything that seems interesting.


Programming Is Tough

It's easy to get discouraged. Some core concepts are tough to master, and compiler / interpreter errors can be very cryptic. Don't quit or get frustrated when you first encounter a problem; keep trying!

Thursday, March 21, 2013

I Like AngularJS (So Far)

I am building a commercial web app using AngularJS that is currently around 3000 lines of JavaScript code (including comments and spacing). I like AngularJS and I'll tell you why.


Monday, January 14, 2013

How-to Launch a Program with SingleAppLauncher

I recently released SingleAppLauncher. It's a tiny .NET program that runs the latest installed version of a single application. If your program automatically updates, this allows for easier program updates.

Here's a quick guide of how to use SingleAppLauncher in your application.

Directory Layout and Configuration

SingleAppLauncher requires a specific directory layout in order to work properly. It must be placed in the root directory of an application, and each program directory (with the .exe to launch) must be a version number. Here's an example adapted from SingleAppLauncher's readme:

C:\App\
  • app.exe (SingleAppLauncher)
  • app.exe.config (SingleAppLauncher's configuration file)
  • 0.91\
    • program.exe
  • 0.92\
    • program.exe
    SingleAppLauncher can be configured in two different ways: configuration file and command-line arguments. For the sake of simplicity, this guide will only cover the configuration file. Here's an example (as a Github Gist):



    In this example, launching 'app.exe' (in C:\App\) will launch C:\App\0.92\program.exe. As of this writing, the version folder names must be exact version numbers according to the .NET Framework's Version class. For example, if the 0.92 version folder was named 'v0.92', SingleAppLauncher will launch '0.91\program.exe'. If both folder names have 'v' at the beginning, SingleAppLauncher will crash.

    Launching Your Program From a Shortcut

    Just have your program's shortcut point to SingleAppLauncher: it will take care of the rest. You should change the shortcut to use your program's icon.

    Including SingleAppLauncher With Your Program

    SingleAppLauncher is released under a permissive license, allowing you to bundle it with commercial and non-commercial software.

    I currently do not distribute SingleAppLauncher in binary form, and (for right now) you should clone the repository from GitHub and build SingleAppLauncher when you build your program.

    SingleAppLauncher currently requires .NET 4.0 to be installed on the build system as well as the client system.

    Saturday, September 15, 2012

    Tech That I Use Professionally

    I started Leavins Software earlier this year. This post discusses the technology that powers the company’s website (www.Leavins-Software.com) and its first product (Leavins Inventory Manager).

    Website

    The first version of Leavins-Software.com used Jekyll. It was a no-brainer for me because I had plenty of experience using it for my personal site. But I soon needed non-static content and server-side data checks. After checking numerous web frameworks, I went with Sinatra. It felt right for the tasks that I needed to do.

    The site uses ERB templates because they’re built into Ruby, they work, and they are more flexible than Liquid templates (used by Jekyll).

    My Sinatra applications run on Thin, which is a good server for Ruby web apps. I chose it for three reasons:
    1. Thin is popular; it’s the most-popular Ruby web server (second behind Passenger, which is more of a deployment option for Apache/Nginx and less of an actual web server) according to Ruby Toolbox (https://www.ruby-toolbox.com/categories/web_servers)
    2. I’ve tried to use Passenger in the past, but deployment (even on a test server) was problematic compared to thin.
    3. Running thin as a user (for development and production) is easy

    My choice of SQL server (PostgreSQL) and load balancing web server (Nginx) was arbitrary. I have worked with Apache and MySQL, and I wanted to try something different.

    Unlike many Ruby web projects, my deployment process does not use Capistrano. If you’re creating a new Rails project, you should use Capistrano or maybe Mina. I found that going off Capistrano’s “happy path” was a frustrating experience, and I needed deviate because I was not using Rails. I may revisit Capistrano at a later time, but my custom deploy script is currently adequate.

    Software – Leavins Inventory Manager


    Leavins Inventory Manager uses WPF for its UI, SQLite (and small bits of XML) for data persistence, and C# as the codebase language of choice.

    I chose WPF over WinForms because WPF produces better-looking interfaces. Early on, Leavins Inventory Manager was actually written to use WinForms, but I managed to convert it to WPF without too much trouble.

    The WPF parts of the application use a mix of MVVM and Code-Behind. I knew about MVVM when I started working with Leavins Inventory Manager, but I did not realize the importance of MVVM in designing major applications. After discovering MVVM and writing my own MVVM framework with support for navigation, I started writing new parts of the app using MVVM. I will likely re-write the entire app to use MVVM, but I don't like to start huge rewrites unless I can dedicate a large chunk of time strictly to the code rewrite.

    The application uses SQLite when convenient. It’s awesome for persisting tabular data in desktop apps. But Leavins Inventory Manager stores program options and order information as XML files. I don’t recommend this mixed approach, but I think that using XML over SQLite in those instances saved me quite a bit of time in developing (and testing) the application.

    Choosing C# as the language was another no-brainer decision. Visual Basic .NET was the first programming language that I learned (other than RCX for Lego Mindstorms), but it’s been a long time since I’ve used it. I used C# at a previous job, and I like it well enough to use it instead of VB .NET. I’m aware of other .NET languages (my favorite being Cobra), but I wasn’t sure if anything besides VB .NET and C# worked well with WPF.

    Sunday, August 26, 2012

    WPF DataGrid and 'Random' ArgumentException

    WPF's DataGrid class seems to have an odd problem. If you put a DataGrid in a ScrollViewer, and if you bind a collection of a type with a specific kind of GetHashCode() implementation, and if you edit data in the grid twice, an ArgumentException will likely be thrown by clicking the data grid a third time. I say "likely" because it sometimes didn't occur on the third attempt. Here's an example stack trace:



    I could not find source code for InternalSelectedItemsStorage's constructor, but it probably calls GetHashCode() to generate a dictionary key. The DataGrid problem is resolved by changing the GetHashCode() implementation so that it gives the same return value even if the name or price of an object changes.

    Here are two examples (one bad, one better) of GetHashCode() implementations.