The Daily Parker

Politics, Weather, Photography, and the Dog

Got some exercise, anyway

After lunch I thought Parker and I could pop around to my second-favorite bar in Chicago, Bucktown Pub, which is about 3 km away. It's a little warm (31°C), so by the time we got there, I was looking forward to cooling off with air conditioning and a gin & tonic.

We left home around 1:15 and got there at 2.

They open at 3.

Oops.

I will now take a shower, and Parker has installed himself directly below the air conditioner.

Git is not Mercurial

I'm pulling the public repository for Orchard again, because I made a mistake with Git that I can't seem to undo. I've set up my environment to have a copy of the public repository, and then a working repository cloned from it. This allows me to try things out on my own machine, in private branches, while still pulling the public bits without the need to merge them into my working copy.

Orchard, which will soon (I hope) replace dasBlog as this blog's platform, recently switched from Mercurial to Git, to which led to this problem.

I may simply not have grasped all the nuances of Git. Git is extremely powerful, in the sense that it will do almost anything you tell it to do, without regard for the consequences. It reflects the ethos of the C++ programming language, which gave everyday programmers ways to screw up previously only available to experts.

My specific screw-up was that I accidentally attempted to push my local changes back to my copy of the Public repository. I had added about six changesets, which I couldn't extract from my copy of public no matter what I tried.

So, while writing this, I just pulled a clean copy of public, checked out the two branches I wanted (1.1 and fw45, for those keeping score at home), and merged with my existing changes.

Now I get to debug that mess...and I may toss it and start over.

Configuring FTP on a moved Azure VM

A couple weeks back I moved an Azure Virtual Machine from one subscription to another. Since then, I haven't been able to connect to the FTP sites that were running on it. I finally spent some time today to figure out why.

First, I forgot to change the FTP firewall support in IIS. The IP address of the VM changed, so I needed to update the VM's external IP address here:

Then, I had to change the FTP firewall support for the FTP site itself. (It looks the same, just on the FTP site instead of on the IIS root node.)

Ronald Door has a good walk-through of how to set this up for the first time on a new VM. The problem is, I'd already set it up on the VM, so I thought that I only had to make the configuration changes I've just described.

Flash forward an hour and a lot of swearing later, and I realized one more problem. See, I set up the VM endpoints through the Azure portal when I launched the VM in the new subscription. However, it looks like I configured them incorrectly. And Microsoft updated the portal last week.

I finally decided simply to delete all four FTP endpoints (port 20 and 21 plus my two passive data return ports) and rebuild them. Endpoint setup is on the Endpoints tab of the Virtual Machine cloud service item:

That worked. The FTP spice flows fine now.

I'm troubled that I don't know exactly why it worked, though. The only difference between the current and previous setup is that before, I inadvertently created load-balanced sets for the ports. Since I only have one VM, that may have been my error.

Learning languages es dificíl

The Atlantic's Ta-Nehisi Coates is learning French:

[T]there's no getting away from the basic feeling of complete idiocy. You are aware of being spoken to as though you were a three-year old, even though you have all the pride of an adult. Worse, if you are like me--a monolingual American in a class where virtually everyone speaks a second language and is now working on their third or fourth--you will be the slowest person. When it comes to comprehension. the Spanish and the Italians are going to just destroy you. They simply have an easier time learning to hear the language than you. This is a gift and curse. Many of the Spanish-speaking students have a much harder time learning the accent. It's as if the closeness of the two languages makes it harder--"parce que" must be be "par-ser-kay" and they will have it no other way.

The hardest thing about learning a language is that, at its core, it is black magic. No one can tell you when, where or how you will crossover--some people will even tell you that no such crossover exists. The only answer is to put one foot in front of the other, to keep walking, to understand that the way is up. The only answer is a resource which many of us have long ago discarded. C'est à dire, faith.

I've recently had the opportunity—requirement, actually—to hold conversations in Spanish, a language I have (in theory) spoken since childhood. Nothing has frustrated me more in the past two weeks than trying to express college-level concepts using my first-grade vocabulary. I also have the horrible habit shared by most Americans: I care too much about the grammar, which makes me stop and re-work what I'm trying to say. In reality, communication may not require remembering exactly how to conjugate an -ar verb in the past subjunctive (e.g., I would have conjugated it if I'd remembered how).

TNC's entire post is worth a read if you've ever tried to do this.

States change their minds about USA/AMR merger

Last week the Justice Department and several states, including Texas and Florida, sued to stop the American—US Airways merger. Today a couple of them realized their error:

Political and business officials in Florida, Texas and North Carolina are asking the U.S. to reconsider its suit to block the proposed merger of American Airlines and U.S. Airways, saying the combined company would benefit their local economies.

Florida, Texas and North Carolina...are home to large hubs for both airlines.

American Airlines, which sought Chapter 11 protection in late 2011, is one of the largest private employers in Miami-Dade County. The carrier operates around 70 percent of the flights at the Miami airport, making it a dominant hub for flights to and from Latin America. Local officials have long promoted Miami as the “Gateway to the Americas.”

Yeah, I didn't understand that four of the six states who joined the Justice Department suits (these three plus Arizona) contain four of the five largest hubs of the two airlines—including the airlines' headquarters (American in Texas and US Airways in Arizona).

Even though I thought there would be a challenge to the merger, after I thought about how the challenge actually went down, it didn't make any sense. Obviously the people who depend on American and US Airways for their livelihoods agree.

Bike-sharing NIMBYs

Chicago has recently rolled out a several hundred DIVVY bike sharing stations, similar to the Citi Bike scheme in New York. For a small annual fee, or a moderate per-hour charge, you can take a bike from any DIVVY bike station and ride it to any other station within two hours. (The two-hour time limit keeps the bikes in circulation.) The city has a hundred or so stations now, with a couple thousand bikes.

Of course, not everyone is happy about the bikes, which help cut pollution, reduce traffic and noise, and are greenhouse-negative. A three-unit condo association near Wrigley Field sued the city yesterday because they don't want Those People on their block:

David Kolin and his wife, Jeannine Cordero, learned Tuesday that the area in front of their North Side condo building soon would be home to a Divvy bike-sharing station, one of hundreds the Chicago Department of Transportation is installing across the city.

"We don't think it's appropriate in a residential area to have this thing set up," said Kolin, an attorney. "It's not a very attractive thing to have. It's led to crowds already."

"It's hideous," added Cordero, also a lawyer. "It's less than 20 steps from our front door."

"We are aware of the request from a few residents to relocate the Divvy station away from their building on Pine Grove Avenue near Addison Street," CDOT spokesman Pete Scales said in a statement. "This residential street location was determined to be the safest for customers near the busy intersection of Addison and Lake Shore Drive. It is located in the public way, close to the curb on the street, and not on any private property."

It would have to be a pair of attorneys, wouldn't it? You don't like the bike rack on the city street in front of your house...why?

All I can say is, Mr Kolin and Ms Cordero: STFU.

Integrating Multiple CRMs with One Azure Cloud Service

(This is cross-posted with the 10th Magnitude Tech Blog.)

Part 1: The Challenge

We developed efox, a Microsoft Windows Azure PaaS application, for our customer Holden International over the course of the last year. Our biggest challenge in the first release was to integrate their flagship sales training application, efox, with SalesForce. But from the beginning of the SalesForce integration effort, we had a constraint we couldn’t ignore: Not only would efox have to integrate with SalesForce, but it would also have to integrate with Oracle Siebel CRM, Microsoft Dynamics, and whatever other CRM application Holden’s customers want to throw at it.

At first glance it looks like a simple problem. Lots of applications, after all, integrate with CRMs. There are also lots of tools to help: SalesForce has a decent SDK, Microsoft has Windows Identity Foundation, most providers (including SalesForce) support OAuth...been there, coded that.

In a typical integration, the custom application extends the service provider’s application. For example, SalesForce has tools to create custom SalesForce extensions that extend SalesForce functionality. An application can run as a SalesForce user and share data with SalesForce transparently, using OAuth and the SalesForce REST API. This is, in fact, how the previous version of efox worked.

efox inverts the problem. Yes, it’s easy to integrate an application with one CRM; but it’s hard to integrate with all of them—simultaneously. At any moment, efox could have several hundred concurrent users going to half a dozen different CRM systems. The application therefore needs to treat each user’s session and each CRM request as a discrete unit.

In this and two succeeding posts, I’ll outline how we solved the architectural problem of separating the UI and back end to abstract away the specific CRM implementation from everything else; how we use ASP.NET MVC 4 routing to let people click a button in their CRM system to launch efox; and how we added single sign-on (SSO) using SAML to allow each user SSO access to efox—or not.

Part 2: The Architectural Solution

Before trying to implement an solution, we first designed the application to handle any arbitrary CRM integration we cared about.

First we created an interface, ICrmIntegration, that exposes these basic operations:

IEnumerable<Account> Accounts(Guid userId);
IEnumerable<Contact> Contacts(int accountId);
SalesPlan GetSalesPlan(string crmOpportunityId, Guid userId);
CrmLoginResult Login(string userName, string password, out string message);
IEnumerable<Opportunity> Opportunities(int accountId);
void Save(SalesPlan salesPlan);

The application uses Factory classes to retrieve objects from the database. We created new Integrated_Factory classes (like IntegratedSalesPlanFactory) that are aware of CRM integration classes and aware of the concrete Factories. Instead of calling the concrete factories, the UI now calls the Integrated factories, which decide whether to retrieve objects from the database or from the user’s ICrmIntegration.

This design completely abstracts the concrete CRM integrations away from the application’s UI. A controller class needing to retrieve a list of Account objects for the user calls IntegratedAccountFactory.Find(userId). That method calls the IntegrationFactory to get the user’s CRM integration (an ICrmIntegration implementation). If IntegrationFactory returns null, meaning the user isn’t integrated with a CRM system, then the IntegratedAccountFactory calls the regular AccountFactory instead. Otherwise it calls the Accounts method on the integration object to retrieve the list of accounts from the user’s CRM system.

Here’s the code in IntegratedAccountFactory:

public static IEnumerable<Account> Find(Guid userId)
{
	var tenantId = AccountFactory.TenantId(userId);
	if (!tenantId.HasValue) return AccountFactory.All(userId);

	var integration = IntegrationFactory.Instance.Find(tenantId.Value, userId);

	return (null == integration) ?
		AccountFactory.All(userId) :
		integration.Accounts(userId);
}

The UI neither knows nor cares whether the particular user gets her accounts from efox, from SalesForce, or from a squirrel; all it cares about is getting a list of accounts. In a sense, this is a classic bridge pattern.

I'll have a couple more posts on efox's CRM integration over the next few weeks. Next up, I'll talk about how CRM integration looks to the end user, then after that, about how we integrated single sign-on (SSO) with multiple identity providers. Check back in a week or so for Part 3.

Still cranky about the Justice Department

Two more opinions this morning about the Justice Department sued to block the American-US Airways merger. First, from Cranky Flier:

[I]f DOJ really wanted to settle for slots at National, it would have done so before filing such a strongly-worded, broad case. Now it has sort of pinned itself into a corner. If it settles, it sets precedent that can be used against it in the future. If it goes ahead with trial, it risks everything.

See, if it goes to trial, then the judge will review the case on its merits. And the end result will be binary. Either the DOJ’s complaint is validated (which still seems unlikely at this point, though we don’t know if DOJ has something more substantial hidden somewhere) or it’s shot down. And if it’s shot down, then the new American not only gets to merge, but it gets to keep all its slots at National and everywhere else. That’s quite a risk to take.

Clearly DOJ thinks that it can win this thing or it never would have taken a chance like this. But it’s a huge gamble. Now we just have to wait and see what happens.

The Economist's Gulliver Blog also weighs in about whether deregulation is to blame:

The consolidation of air service at central hub cities is bad news for cities that aren't hubs. But it's great news for the cities that are. It's good for airlines that are saving money by shutting down inefficient routes. If it's encouraging businesses and people to move to more densely populated areas, well, there are numerous economic and environmental benefits to having people live and work closer together. And the loss or decline of network carrier service to some small airports has fuelled the rise of ultra-low-cost carriers at some of those same airports. All of which is to say: the decline of small and medium-size airports is less of an unmitigated disaster and more of a mixed bag than Mr Longman and Ms Khan make it out to be. Returning to a more regulated airline industry would be a huge political lift with countless unintended consequences. It's worth thinking about how deregulation has changed the face of the airline industry. But the troubles of America's smaller airports—and the communities they serve—have roots far deeper than the demise of the Civil Aeronautics Board.

The merger will, of course, cause some more consolidation. The alternative is that we have two giant global airlines and two smaller ones that can't possibly survive much longer.