Monday, June 22, 2015
The Single Page Application (SPA) approach makes web development look more like traditional client development in that a lot of state is maintained and manipulated entirely on the client.
One of the core features of Angular is rendering multiple elements of an array (e.g., Orders, Customers, etc...). This can be done with the ng-repeat element or the ng-options attribute to a select list.
With ng-options, if the model backing the selection (the model that stores the currently selected value) is a scalar (e.g., an integral ID, a unique string code, etc...) I've found that using the select as form of ng-options works best. For example, for a dropdown list of customers the model might be a unique customer ID. In this case:
ng-options="customer.customerId as customer.fullName for customer in customers"
allows angular to correctly identify the currently selected customer in the array of customers. This is especially important for models that store previously saved selections.
If, on the other hand, the model is an object (non-scalar), e.g., a customer, then I've found that the label for/track by form of ng-options allows angular to correctly identify the currently selected customer. In this case:
ng-options="customer.fullName for customer in customers track by customer.customerId"
This is handy when the model expect an object for the corresponding property in the underlying Data Transfer Object (DTO).
Tuesday, February 25, 2014
In the startup world when you discover an issue, whether it's a logic error or an environmental misconfiguration, being able to fix it quickly and, maybe, document the fix is a virtue.
A hard lesson that I'm learning is that in a different environment that which was a virtue in the startup world can actually be harmful. By fixing an environmental issue you can deprive the organization of the process correction necessary to handle it structurally.
This strikes me as analogous to the decision to *not* handle an error in code. Sometimes you intentionally don't handle an error even though it is anticipated because to do so masks a more fundamental problem. The "if this error occurs, something is deeply wrong in a way that can't be recovered automatically" is a widely established pattern in software construction.
The hard part is realizing that it generalizes to the organizational level. By fixing an environmental issue that another team is responsible for you may well deprive that team of a needed corrective. What happens when you're too busy working on problems that can only be handled by your team and the issue comes up again?
Saturday, February 22, 2014
If the middle layer reaches back up into the top layer then you've created a circular dependency. Circular dependencies make a system harder to understand (and therefore maintain). One way in which they do this is their tendency to create chicken-egg problems. Put another way, they introduce another axis of dependency (order/time) that may not be obvious from inspecting the code. Chicken-egg problems aren't necessarily intractable, clearly *something* came first, but by adding another dimension they exponentially increase the size of the solution space making for many more blind alleys in which to get lost.
Working on a large system built up over time by many different contributors has given me a much greater appreciation for the importance of this basic architectural principle. This is a bit of a hard-learned lesson because it tends against one of my favorite design principles: the composite pattern. A layer built based on the composite pattern can reference itself as well as lower layers. I'm playing a little loose with the terminology here because layers generally refer to larger pieces of a system while the composite pattern is usually applied to smaller pieces of a large system but bear with me.
Let's take a hypothetical system called Manuals. The Manuals system is maintained by the Manuals team. Manuals depend on Chapters. Chapters depend on Sentences. Sentences are the lowest level of the system - this is where the meat of the work is done. The higher layers (Chapters and Manuals) are primarily about organizing/ordering the work of Sentences.
A few months after the Manuals system ships Developer X encounters it and, being fresh full of ideas about design patterns, thinks it would be really useful if Chapters could be composites. That is, he'd like Chapters to be able to contain Sentences and Chapters. He thinks the system would be so much more expressive that way. And it would enable reuse at the Chapter level. Who doesn't love wringing more expressivity and reusability out of a system?
Fast forward 2 years. Half a dozen developers have rotated in and out of the project each with varying levels of expertise, varying exposure to the original designs and different constituents to satisfy. None of the original developers is still working on it. The design docs, which were originally shared on the shiny, linky (e.g., non-duplicative) intranet were lost long ago somewhere between conversions to Intranet v2 then v3 and now v4 (the current version). Even if they could be found they'd be horribly out of date as the codebase is 10 times its original size. You're tasked with what should be a simple fix: change the wording of a boilerplate sentence that appears in nearly every Manual produced since the project originally shipped.
Being new to the project what do you do? You look at the manuals you can find. You see that each Manual appears to be made up of Chapters and each Chapter appears to be made up of Sentences. So you start your search in the Chapter directory and change every instance of the boilerplate sentence in each of the Chapters.
In a system that maintains the downward flow of dependencies (Manuals -> Chapters -> Sentences) there's a very good chance that this particular bug has been quashed: the boilerplate sentence is updated everywhere it will appear.
But what if Chapters were Composites in the system: they contained both Sentences and Chapters? Although originally all the Chapters were in a single directory, someone once accidentally chose a Chapter name that was already in use (without knowing it) so there was a major refactoring project that moved Chapters contained by other Chapters into other directories. A few months after that refactoring there was a big push to support the creation of chapters by another team. The Manual team just didn't have the bandwidth to handle the demand for Manuals. But the other team stored their artifacts in a different location. So to keep them productive the Manuals team added support for chapter references - pointers to chapters defined in other locations.
Now the job of changing a single boilerplate sentence everywhere it appears has gone from being a grep/findstr in a single directory to a programming task in and of itself. One that crawls Chapter references and looks for boilerplate sentences in the pointed-to Chapters. And doesn't crash on stale references. And doesn't infinitely loop when circular Chapter references are found. All because the downward flow of dependencies was broken when the elegant composite pattern was introduced into the system.
Sunday, December 22, 2013
It also seems not to like the 5Ghz channel (from an Asus RT-N66U) though this was true under Win 7. So I upgraded to an Intel 7260 which is performing flawlessly.
BEFORE Changing the WiFi card
- Download the Middleton BIOS iso.
- Download rufus from pendrivelinux.com
- Follow the instructions at pendrivelinux to format the usb drive as a bootable DOS disk.
- Copy the files from the Middleton BIOS iso to the usb drive. (either mount it or use 7-zip to extract the iso contents).
- Make sure your battery is near fully charged (battery icon is green not yellow on thinkpad indicator).
- Disable the TPM chip in the bios.
- Suspend BitLocker if it's on.
- Boot from the USB drive.
- Run the flash utility (lcreflsh.bat).
- Wait for several minutes.
Changing the WiFi card
- Follow the instructions here for removing the wifi card.
- Insert your replacement wifi card.
Wednesday, December 18, 2013
I decided to stick with an Asus (pronounced uh-soos) motherboard and picked up their Z87-Plus. The board being replaced, the P6T, was also an Asus board. Come to think of it, so was its predecessor (the A8N-sli). Before that it was an Intel board. Even though I don't do much overclocking I love the attention to detail that Asus puts into its products. And its website is well organized - always easy to find drivers. A few years back a quick comparison of their website to the website of their competitors (Gigabyte, MSI, etc...) sent me flying into their arms. They're not the least expensive boards but I've had good experience with them.
I fallen in love with the front panel header connector they ship with their boards. You plug the front-panel connectors (power LED, reset switch, PC speaker, etc...) into the connector (pictured below) then plug the connector into the board. It's a lot easier to swap out motherboards because you don't have to reconnect the sometimes lilliputian shunts onto single pins.
|Front Panel Connector|
|CPU and stock fan|
|UEFI BIOS for Asus Z87-Plus|
|UEFI BIOS Confirmation Dialog (apologies for the fuzzy picture)|
As a pc hobbyist since the mid 90s it amazes me how much easier it has become to build your own PC. I haven't cut myself on an add-on card or connector in going on 10 years. :)
MSBuild seems to take the object oriented metaphor a little deeper as it relates to XML. That is, both the verbs of the system (Targets and Tasks in msbuild-speak) and the nouns of the system (Properties and Items) are represented as elements. The best way to get a handle on these concepts is to peruse "MSBuild Concepts"
One of the first gotcha (there are always gotcha moments with build systems) moments I've encountered has been related to the Exec task. It's a built in task that ostensibly executes any command passed to it. Except that it seems to not like managed executables. Or parameters with whitespace (yep, 2013 and whitespace is still dangerous). It'll happily open notepad.exe (even without a fully qualified path) but chokes on a "Hello World" C# console app. But not a C++ "Hello World" app. And the exit code is usually -21474.... which to any programmer looks a lot like -(2^31) - 1 and is usually indicative of a bug lurking somewhere.
Fortunately it's pretty straightforward to roll your own Task. I love it when they provide both an interface and a handy default implementation so that you only have to override the behavior in which you're interested.
If you're doing anything other than calling cmd.exe intrinsics (e.g., echo, dir, etc...) then I highly recommend doing it inside a custom task.
Wednesday, December 11, 2013
printui /s /t2
Make sure to remove the printer from devices and printers first.
Make sure to remove the right printer (e.g., one that's using a compatability print driver will require deletion of that compatability print drivers as well as the device specific driver).