CODE Magazine - May-June 2016
CODE Magazine - May-June 2016
MAY
JUN
2016
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95
Features
8 Parse is Set to Shut Down. Now What? 60 Implementing Lean Controllers in iOS Applications
It seems like only yesterday that Facebook acquired Parse so that Have you been struggling with sluggish apps? Perhaps all that’s needed
developers could focus more on the frontend than the backend of their is a little tightening of the code. Mohammad makes your apps lean and
apps. In January 2017, they’re shutting Parse down. mean again with a simple ToDo example.
What’s a developer to do? Jason tells us what our options are. Mohammad Azam
Jason Bender
64 SQL Server Reporting Services: Eight Power Tips
12 The Journey to Angular: Part 1
SQL Server’s Reporting Services is still the best workhorse for getting
When you wrap your JavaScript code into a closure, you won’t have data to your users. Kevin tells you how to take advantage of some of
bugs caused by unnecessary variables. Paul shows you how to do this its more subtle points.
using a templating tool called Mustache, which will help you get closer Kevin S. Goff
to coding in Angular.
Paul D. Sheriff
18 AngularJS 2
Sahil shows us a few nifty aspects of AngularJS 2 that help experienced
and novice developers alike. AngularJS 2 is still in beta, but he says
Columns
that you’ll love it even so. 74 Managed Coder: On Responsibility
Sahil Malik Ted Neward
Departments
If you want your Web page to hold audio recordings that play when users
want them to, you’ll want to read John’s article. He shows you that it’s
not only quick, but it’s easy!
John V. Petersen
6 Editorial
28 Why F# Code
Functional programming is all the rage and Microsoft’s foray into the functional 10 Advertisers Index
world is called F#. Rachel introduces you to this first-class functional language
with the ability to harness the rich .NET ecosystem.
Rachel Reese 73 Code Compilers
34 Arranging Views with Xamarin.Forms Layout
There’s no longer a simple answer to what sort of device your page will
be viewed upon. Walt examines the options and shows you how to
make sure that yours will look great on anything, old or new.
Walt Ritscher
US subscriptions are US $29.99 for one year. Subscriptions outside the US pay US $44.99. Payments should be made in US dollars drawn on a US bank. American Express,
MasterCard, Visa, and Discover credit cards are accepted. Bill me option is available only for US subscriptions. Back issues are available. For subscription information, send
e-mail to subscriptions@codemag.com or contact customer service at 832-717-4445 ext 028.
Subscribe online at codemag.com
CODE Component Developer Magazine (ISSN # 1547-5166) is published bimonthly by EPS Software Corporation, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
POSTMASTER: Send address changes to CODE Component Developer Magazine, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
Canadian Subscriptions: Canada Post Agreement Number 7178957. Send change address information and blocks of undeliverable copies to IBC, 7485 Bath Road, Mississauga,
ON L4T 4C1, Canada.
Creative Fear
The SXSW Interactive conference has a section of the conference dedicated to the concept of
mentorships. It works like this: As a mentor, you meet with attendees who sign up for seven-minute
meetings. These meetings are free form and the attendees can ask whatever they want of their mentor.
My mentorship sessions tend to revolve around I had a great conversation with Melanie Spiller The point is to find people who’ll give you honest
three tent-pole areas of my career: writing, being (the person who makes our authors, including me, and constructive criticism. You don’t necessarily
a software developer, and being an independent sound so good) about the aspect of fear in cre- have to be told how to fix it, but knowing that
consultant/business owner. It’s an honor and ative endeavors. Melanie and I both have inter- something doesn’t work puts you closer to the
privilege to be a mentor. In my 20+ years as an ests outside of the software development/tech- right path.
independent software developer I‘ve been a men- nology realm. Melanie’s an accomplished singer
tor to many of my colleagues and friends and I as well as a great writer, and I have a passion for
take the job seriously. film, especially the creative process surrounding Just Do It
film’s creation. There’s another trait that we both Sometimes you just need to put one foot in front
I’ve been a mentor at SXSW for a few years now share as well: The fear of turning artistic fantasy of the other and go for it. Write that script, get
and for the first few years, no-one showed up for into reality. In my case, I’m kind of scared witless that camera and shoot that photo, break out the
their scheduled session. Admittedly, this was a bit to create my own film. Numerous cautionary tales journal and start that book—just go for it. What
of a disappointment. Some of my friends asked and random trepidations creep into my mind: do you have to lose?
why I continued to participate in the program. My What if I don’t like creating my own movie? What
answer was simple: If someone shows up, the sev- if I can’t find people to help me? What if I make
en minutes I give him or her could be life-chang- a movie and it sucks? And Melanie tells me that Rod Paddock
ing. Not to be egotistical, but I firmly believe that she’s revised her book 11 times (that’s right, the
seven minutes of good advice, or encouragement, whole shebang, rewritten from start to finish 11
can make all the difference in a person’s life. times!) over numerous years and with the help/
advice of various writing groups and agents, and
This year, I might have had that affect. My last despite more than one agent saying “yes,” she’s
appointment of the day was a software developer expressed similar fears to me and describes her
from Boston, who, with some other software devel- current status as “blocked.”
opers, was about to quit the world of W2 employ-
ment and “hang a shingle.” This software team is How do you get over these creative fears? Here
putting together a set of tools for building custom- are a few ideas.
ized chat bots. It was an interesting concept and
looked to be well-architected. I gave him the same
advice I’ve given other colleagues over the years: Ask for Help
get a CPA, set up an LLC or corporation with the This is exactly like the software developer in my
help of a lawyer, make sure the ownership of the mentorship story. Seek out the advice of other
intellectual property is properly documented, etc. people who’ve done it before. Consider their ad-
vice and leverage their knowledge as you pursue
After having a rich conversation about his busi- your endeavors. It’s not a sign of weakness—it’s a
ness and architecture, we chit chatted for a while sign of strength to know what you need and how
and I told him something that set him back a bit. to get it.
I told him that he’s way ahead of so many other
people. The simple act of showing up for our men-
tor session set him apart from 75% of the other Form a Circle of Trust
people who failed to show up. That commitment In any creative endeavor, you need to have peo-
to making himself better, accompanied by the ple that you can send your work to who will set
leap it takes to start a new endeavor said much you straight when something works and, better
more about the person than the business idea. It yet, when something doesn’t work. One of my
takes guts to set out on your own and it takes friends in Austin is a professional screenwriter/
smarts to ask for advice about starting out. He author and I’m part of his “Circle of Trust.” He
had both of these elements, guts and smarts. I relies on me to give honest advice and I’m al-
hope he succeeds in his endeavors. ways happy to do that. For one of his scripts, my
advice was something like this: “These sections
This leads me to the subject I want to really talk sound like bad episodes of Law and Order and
about: Getting over fear in the creative process. you should drop or trim them as they do nothing
Being creative can be exhilarating and scary at for the story.” If all he wanted was praise for his
the same time. lovely prose, I bet I’d be out of the circle quickly.
6 Editorial codemag.com
ONLINE QUICK ID 1605021
Facebook acquired Parse in 2013. In 2014, Parse released the dependency on a third party. As made evident by Parse
a report detailing their support of over 500,000 applica- shutting down, relying on a third party to support your
tions. On January 28, 2016 Facebook announced that it business’s infrastructure can negatively impact you in the
would shut Parse down with all services ceasing operation long term should the service get discontinued or its prod-
on January 28, 2017. uct undergo a radical change.
• User management and authorization using AWS Figure 2: Client-to-backend relationship after the first phase of Parse’s migration strategy
Cognito
• NoSQL and SQL databases using AWS RDS and AWS
DynamoDB
• Push Notifications using AWS Simple Notification
Service
• App Analytics using Amazon Mobile Analytics
• Cloud-based logic using AWS Lambda
• QA against real devices in the cloud using AWS De-
vice Farm
Although this option likely gives you the shortest path to Sooner Rather than Later
migrate off of Parse’s services, you should also consider Whichever approach you decide to take, it benefits you
the downside to this approach. Mainly, the open source to move quickly. Parse announced that if you haven’t
server doesn’t come with all the bells and whistles that at least migrated your data source by April 28, 2016, it
largely made Parse desirable to begin with; items such would de-prioritize the traffic to your application in favor
as the dashboard (Parse mentions that they’re working of applications that have already made that transition.
on an open-source version), push notifications, analytics, They also formally suggest that you try to complete your
webhooks, general application configuration, cloud code, migration off of their services by July 28, 2016.
and scheduled jobs will all need to be substituted if your
application is dependent on them.
If you haven’t at least migrated
Additional Parse Substitutes
Lastly, the BaaS ecosystem has a number of players that you your data source by April 28,
could consider if you’ve determined that you want a substi- 2016 Parse will de-prioritize
tute and would rather re-engineer your client-side applica- the traffic to your application
Amazon Migration Plan tions instead of taking up backend development. The follow- in favor of applications
ing list details some of the more popular options. The sidebar that have already made
https://aws.amazon.com/mobile/ contains additional links to a more comprehensive list.
getting-started/ details Amazon’s that transition.
official strategy for moving an • Kinvey: A BaaS platform very similar to Parse and
existing Parse application to
offering cloud storage, push notifications, and cus-
AWS using Elastic Beanstalk.
tom business logic. Unlike Parse, the free tier is The options listed in this article represent a small sample
development-only. of the choices that you have to consider. If you want to
Heroku • Firebase: NoSQL cloud database that specializes in check out more options, look at the sidebar for several
real-time communication. Data is stored in JSON additional resources. Additionally, when considering one
https://www.heroku.com/
objects and is then synced to all connected clients of the Parse alternatives, keep an eye out, as most have
Heroku is a cloud platform based in real-time. tutorials specifically created to help developers transition
on a managed container system, • CloudKit: An iOS- and OSX-specific public and pri- from Parse to their respective platform.
with integrated data services vate cloud database that has a point-click dash-
and a powerful ecosystem, board similar to Parse. Jason Bender
for deploying and running • Microsoft Azure Mobile App Service: Similar to
modern apps. Parse in that it also does both offline/online data
ADVERTISERS INDEX
Advertisers Index
SQL Reporting Services, ASP.NET MVC, AngularJS, F#, Life after Parse 1&1 Internet, Inc. dtSearch
www.1and1.com 7 www.dtSearch.com 55
MAY
JUN
2016
AnDevCon Hibernating Rhinos Ltd.
www.andevcon.com 43 http://ravendb.net 5
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95
Sample Code what it does. You’re not interested in creating the whole page and just change the format of those to match what’s
project in this article, just how to wrap up the different presented in this article.
You can download the sample functions into the closure.
code for this article by visiting my
website at http://www.pdsa.com/ The HTML page from the last articles lists, adds, edits, Templating with Mustache
downloads. Select PDSA Articles, and deletes product data. This page contains 19 functions Concatenating strings in JavaScript as I did in the pro-
and then select “Code Magazine within the <script> tags. Of these 19 functions, only five ductTableBuild() function is a horrible way to generate
- The Journey to Angular - Part 1”
need to be made public. There’s also one global variable HTML. It’s very difficult to read, hard to debug, and leads
from the drop-down list.
called Product. This variable becomes a private variable to runtime errors. Instead, let’s employ a technique
within the closure, as that’s the only place it needs to be called templating by bringing an open-source library
referenced. Listing 3 is what your closure looks like for called Mustache into the project. You can download this
all 19 functions. I removed all of the code from within the very small library at https://github.com/mustache/mus-
functions so you can just see how everything is enclosed tache.github.com. Once you download it, add the mus-
within the IIFE. tache.min.js file to your project and reference the library
in your HTML page using the following tag:
Remember that after wrapping your functions into a clo-
sure, you need to reference the closure variable in front <script src="/Scripts/mustache.min.js"></script>
of your functions. This includes your event handlers. If
you added your event handlers into your closure, you In Listing 2, the function productTableBuild() is used to
need to make sure they are made public. You also need to build HTML table rows in JavaScript. You’re now going to
change the HTML that calls these event handlers. Add the eliminate the code in that function and replace it with
name of your closure variable in front of the calls to the code to process a template. To do this, you need to do
event handlers, as shown in the next code snippet. Notice three things. First, add a public function in the closure to
the controller. that was added prior to the updateClick() expose the collection of product objects contained in the
function name. products variable.
productList: function () {
getProducts().done(function () {
productTableBuild();
});
},
productList: function () {
$.ajax({
url: BASE_URL,
AngularJS 2
AngularJS has been a huge success. More than 1.1 million developers have embraced this platform and created thousands
of applications using it. Writing complex applications in JavaScript can be challenging, and AngularJS made it approachable.
In a language devoid of good design patterns and strict rules, AngularJS brought sanity and consistency. But let’s be honest;
although AngularJS was a huge improvement over writing • It allows for a more logical code structure than its
JavaScript by hand, it did have some issues. Learning An- predecessor. AngularJS 1 had the bad habit of pol-
gularJS was a steep curve. Buying into it was embracing luting your HTML, not giving you more control on
the whole platform. And most of all, there were so many CSS, and forcing you to think in MVC. AngularJS 2
ways to do it incorrectly, and so many ways to do it better allows you to do MVC, or Flux, or any other design
than the last developer. pattern you wish. It also allows you to logically de-
sign and arrange your application in components
Over time, as browsers improved and Web technologies rather than controllers. And finally, it tends to pol-
were applied to more than just browsers, AngularJS 1 lute your HTML less, and only in ways that seman-
NameMalik
Sahil Autor didn’t take full advantage of those scenarios. Plus, Type- tically enhance HTML. You don’t need ng-href or
www.winsmarts.com
www.internet.com Script, which, in my mind is the single most important ng-src, but you can still have your own tags, like
@sahilmalik innovation in JavaScript since fast JavaScript engines, al- <customer/>, etc.
asdfasdfasdfasdfker, a .NET ways felt like an afterthought in AngularJS 1. Yes, although • And the best part about AngularJS 2 is that it’s
Sahil
author,Malik is a Microsoft
consultant MVP,
and trainer. you could use TypeScript, it was hard to take full advantage easier than AngularJS 1. I’ll be honest, it took a lot
INETA speaker, a .NET author,
of it unless you consciously attempted to do so. As a result, of time to truly master AngularJS 1. And there were
Sahilasfasdfasdfasdfasdfasdfd-
consultant, and trainer.
fainings are full of humor and in an AngularJS 1 world, you are more likely to see lots of so many ways to mess it up. Parent scopes can be
Sahil loves
practical interacting
nuggets. withfind
You can fel- JavaScript or incomplete usage of TypeScript. so complicated. As my applications got bigger, my
low
moregeeks
aboutinhis
realtrainings
time. Hisattalks head exploded. Developers smarter than me crafted
and trainings are full of humor
http://wwasdfasdfasfasdfasdf This is not unexpected: Times change and technologies amazingly intricate card houses that collapsed eas-
and practical nuggets. You can evolve. AngularJS 2 is a natural evolution of AngularJS ily. I felt like an idiot. And this was after a few years
find more about his training at 1. AngularJS 2 brings it up to date with modern Web of AngularJS 1. AngularJS 2, on the other hand, felt
http://www.winsmarts.com/ standards, better design patterns, and takes advantage of a lot more logical, and it was easier to understand
training.aspx. what’s new and awesome today. and learn. I find myself more productive in Angu-
larJS 2, and I have the confidence that I’m writing
His areas of expertise are cross- more reliable and easier-to-maintain code. Much
platform mobile app develop- Why Bother with AngularJS 2 more so than AngularJS 1.
ment, Microsoft anything, and There are four main reasons you should seriously consider
security and identity.
AngularJS 2: The obvious elephant in the room of course is that Angu-
larJS 2, at the time of writing this article, is still in beta.
• It is fast. Very fast. It takes full advantage of mod- Still, I like AngularJS 2 so much that even in beta, I have
ern Web browsers and defaults to using the capa- no reservations in recommending this platform for new
bilities they offer to give you the best performance. development over AngularJS 1, especially if your release
If you wrote the same functionality in AngularJS 2 date is in the second half of 2016.
as you wrote for AngularJS 1, AngularJS 2 will most
likely far outstrip the performance of AngularJS 1.
• It is portable. Although it relies on the newest Thinking in AngularJS 2
standards, it uses polyfills to support almost every AngularJS 2 requires you to think differently. There are
browser you care about. Even IE9 is supported. some key differences compared to AngularJS 1, features
you need to learn and decisions you need to make. The
good news is that even though there are differences be-
Listing 1: AngularJS 1 Controller tween AngularJS 1 and AngularJS 2, many concepts port
(function () { over. As an AngularJS 1 developer, you’ll clearly see the
angular improvements where you see the differences. As a new-
.module(‚app‘, []) to-AngularJS 2 developer, you’ll find the new syntax and
.controller(‚appController‘, appController) features easier to learn.
function appController() { With that, let me go through the various differences, fea-
var vm = this; tures, and key decisions.
vm.name = „Sahil“;
} Language Choices
})();
JavaScript is evolving. It needs to, because the original
language simply isn’t going to scale to the level of the
complex applications that you need to build. When writ-
Listing2: Using an AngularJS 1 controller
ing for AngularJS 2, you have various choices:
<body ng-app=“app“ ng-controller=“appController as vm“>
Name: <span ng-bind=“vm.name“></span> • ES5: The obvious advantage of using ES5 is that it’s
</body> only JavaScript and it needs no compilation. But
18 AngularJS 2 codemag.com
it’s not strongly typed, and it doesn’t offer the code Listing 3: An AngularJS 2 component
structure advantages of other alternatives.
import {Component} from ‚angular2/core‘;
• ES6: ES6 is a superset of ES5. Although it does
give you some better code structure building
@Component({
blocks, it isn’t strongly typed, and it needs a com-
selector: ‚my-app‘,
pilation step. At the end of the day, it’s JavaScript,
template: ‚<h1>Hello {{name}}<h1>‘
and with time, browsers will support ES6 natively. })
It’s sure taking a very long time for them to do so.
• TypeScript: TypeScript is a superset of ES6. It’s export class AppComponent {
strongly typed. It gives you much better code name = „Sahil“;
structure building blocks, but it requires a com- }
pilation step. At the end of the day TypeScript is
JavaScript—okay, it’s a superset of JavaScript,
but you can rename your .js to .ts and pretend it’s
Listing 4: Bootstrapping an AngularJS 2 app
JavaScript.
• Dart: Dart seems to offer the worst of all worlds. import {bootstrap} from ‚angular2/platform/browser‘
It isn’t JavaScript and it requires compilation, but import {AppComponent} from ‚./app.component‘
it gives you better code structure alternatives. bootstrap(AppComponent);
Because it’s not a super set of ES5, ES6, or
TypeScript, using Dart feels like using an entirely
different language that doesn’t mentally translate Listing 5: Structural directives in AngularJS 1
into JavaScript. At least, not easily. <ul>
<li ng-repeat=“hobby in vm.hobbies“>
Given the above choices, I feel that we have a clear win- <span ng-if=“!hobby.hide“>
ner, and that’s TypeScript. I’m going to write my Angu- {{hobby}}
larJS 2 code in Typescript, and apparently the AngularJS </span>
2 team is doing so too. You are, however, free to use ES5, </li>
ES6, or Dart. But I don’t see why you wouldn’t prefer to </ul>
use Typescript.
Controllers, over time, became very complex. They had to AngularJS 2 takes a different approach. AngularJS 2 likes
deal with parent and child scopes. There was no one-size- to split your application into components. And it allows
fits-all approach that you could use, making understand- you to bootstrap the starter component by importing it as
ing and debugging the application for the next developer a module first. This can be seen in Listing 4. This gives
a lot harder. And it forced you to do MVC, whether or not us a lot of control in modularizing the application. Be-
it was the right choice for your application. cause the module is a class that you export, you have
very clear control of which portions of the module are vis-
AngularJS 2 replaces “thinking in controllers” with ible and which are not. You can also bootstrap condition-
“thinking in components.” Components are the central ally; what’s perhaps most interesting is the first line in
artifact in AngularJS 2. Listing 4. AngularJS 2 imports bootstrap from angular2/
platform/browser. This means that the browser is sepa-
<my-app>Loading...</my-app> rate from the core AngularJS 2. You could theoretically
have different bootstrapping functionality for Cordova/
Using the component shown in Listing 3 is a matter of Electron etc.
referencing the selector. The component can nest other
components, and it can even give your “tag” its own CSS Structural Directives
area, so your CSS doesn’t interfere with the page’s CSS There are three kinds of AngularJS directives: there are
and vice versa. components; there’s a directive with a template in An-
gularJS 2; and there’s the attribute directive, which can
Bootstrapping change the behavior or appearance of an element (for ex-
Bootstrapping your app requires explicit action from you. ample, NgStyle); and structural directives.
AngularJS 1 allowed you to bootstrap your app by placing
certain attributes in your HTML, as shown in Figure 1. Or Structural directives can alter the structure of the DOM.
alternatively, you could bootstrap your app in AngularJS For instance, ngIf, ngSwitch, ngFor are structural direc-
1 using code also. tives.
codemag.com AngularJS 2 19
Listing 6: Structural Directives in AngularJS 2 Why am I using ng-bind to change the value of innerText?
And what if I wanted to bind to an alternate property such
<ul>
as CSS or width or href? This is where AngularJS 2 uses a
<li *ngFor=“#hobby of hobbies“>
much better syntax, as shown here:
<span *ngIf=“!hobby.hide“>{{hobby | json}}</span>
</li>
<span [innerText]=“name“></span>
</ul>
As you can see, the syntax is slightly different, but it still The same affect can be achieved in AngularJS 2 using the
works. “banana in a box syntax” or the [()] expression as shown
below:
Now here is the really interesting part. You can write your
own structural directives in AngularJS 2 using the @ <input [(ngModel)]=“name“>
Directive decorator. This gives you very fine control on
exactly how you want the DOM to be modified. Modifying This cleaner syntax of databinding that AngularJS 2 uses
the DOM is one of the most expensive things your appli- has another side benefit: You have fewer directives to
cation does, so this level of control is definitely very wel- learn.
come. Sure, you could do this in AngularJS 1, but there,
everything was a directive, and writing directives could Fewer Directives to Learn
get complex. AngularJS 2, with its @Directive decorator, Here’s an AngularJS 1 quiz. What did ng-href do? If you
puts writing complex directives within the reach of mere remember, you couldn’t databind directly to the href
mortals. property of an anchor tag in AngularJS 1. This is because
the browser understood the expression before the result
DataBinding of the expression, thereby breaking your href location.
Databinding is what truly set Angular apart. There are Not good! So you had to create directives like ng-href,
three kinds of databinding that AngularJS supports: In- ng-src, etc.
terpolation, one-way databinding, and two-way databi-
nding. Let’s look at them: Similarly, you had numerous other directives, such as
ng-style to modify the style of an element. Or ng-click,
• Interpolation, the {{expression}} double-mous- ng-blur, etc. to handle events! Because AngularJS 2 al-
tache syntax. Both AngularJS 1 and AngularJS 2 lows you to databind with a much more intuitive syntax
support interpolation in exactly the same manner. using the property name instead, all those directives are
The key difference is that AngularJS 1 databound no longer required.
to properties on the view model or $scope of the
controller. AngularJS 2 databinds to exported prop- For example, consider the following AngularJS 1 code:
erties of the underlying class that the component is
implemented as. <img ng-src=“vm.link“/>
• One way databinding, using ng-bind. This is where
AngularJS 2 shows its superiority over AngularJS 1. This can be simplified in AngularJS 2 as follows:
AngularJS 1 required you to do one way databind-
ing using the syntax shown below: <img [src]=“link“/>
Name: <span ng-bind=“vm.name“></span> And you can guess that you don’t need ng-click either,
because you can databind directly to the click property. In
This syntax was functional, but it required you to inter- fact, AngularJS 2 has removed the need for 40+ directives
sperse attributes that sometimes were not very intuitive. because of this superior syntax.
20 AngularJS 2 codemag.com
Services versus Class • Modules: AngularJS 1 and AngularJS 2 both have
It was very easy to abuse controllers in AngularJS 1. As a modules. But AngularJS 1 couldn’t make use of ES6
best practice, we were advised to abstract the heavy lift- modules because ES6 wasn’t around when Angu-
ing to services. But services weren’t just services. There larJS 1 was born. AngularJS 2 uses proper ES6 mod-
were Services, Providers, and Factories – three ways to ules, but yes, the concept of modules is still around.
create Services (and not very intuitively named, either). • Filters: Remember in AngularJS 1 there was a fil-
And then there were constants, values, and the config ter called “filter”? Confusing? They’ve changed the
method etc. on your module. You had to know exactly name of Filters to Pipes! It’s much more logical, es-
which one did what, and which got called before the oth- pecially given the syntax. But the concept is still
er. This innate knowledge of the nature of provider versus around.
service versus factory and config versus run, or constant • Routing: Routing in AngularJS 1 has undergone
versus value left many of us confused. It made the learn- evolution and improvements. The routing in Angu-
ing curve unnecessarily steep. lar 1.5x is quite similar to routing in AngularJS 2.
• HTTP: Because you need to interact with the server
But why did AngularJS 1 have to do all that? It was mak- too. The same concepts apply in Angular1 and An-
ing up for the shortcomings of JavaScript. AngularJS 2 on gular2.
the other hand has a class. A class can have a constructor, • Events: These are still around, but you have a much
exported properties, getters and setters, etc. And with better and logical syntax using event emitters.
TypeScript, the way you write these classes is also very There will be more on that in future articles.
second-nature to those coming from other languages • Promises: are still in there. AngularJS 2 has chosen
such as C# or Java. to give us another option, built on RxJS, called Ob-
servables. Observables can be thought of as a data-
In that sense, AngularJS 2 is much simpler to write and source of events that you can filter on. It’s a much
maintain because all those concepts are subsumed by the better architecture and it’s come out of reactive ex-
concept of a class—something you already know. tensions for C#. If you’ve used reactive extensions
in either JavaScript or C#, you probably already
Dependency Injection know that once you go RxJs, you don’t go back!
Dependency injection is a software design pattern that
implements inversion of control for resolving dependen- Perhaps the improvement I like the most in AngularJS 2 is
cies. A dependency is an object that can be used (such as much better error messages. As a developer, I’ve wasted
a service). An injection is the passing of a dependency to way too much time over poorly worded generic error mes-
a dependent object (a client) that will use it. sages. AngularJS 1 tried, it tried hard to give me a decent
error message about a typo. But frequently an ng-click
Dependency injection is a strength of AngularJS. It allowed mistyped as ng-clik yielded no error message. Stuff just
us to change the behavior of code at runtime by passing in didn’t work! Even when I did get an error message, it
the appropriate dependencies. This was achieved in Angu- looked like a cryptographic version of a SharePoint site
larJS 1 using the code shown in Listing 7. collection GUID salted in Russian. I am happy to say that
AngularJS 2 error messages are usually a lot cleaner and
It worked, but it had a huge downside: The magic string more intuitive than their AngularJS 1 counterparts.
problem. The MyService is a string in Listing 7, and if you in-
troduced a typo, it broke your code. What was worse, Angu-
larJS 1 allowed you to write variable names such as $scope Summary
and $http, and AngularJS 1 attempted to resolve those for This article isn’t intended to be an AngularJS 2 tutori-
you. Because a lot of code online showed such patterns, the al. It’s intended to illustrate the key improvements and
typical Google-driven development workflow meant that a changes and the reasons behind them. It’s intended to
lot of developers copy-and-pasted that code and painstak- illustrate why I’m excited about AngularJS 2 and why any
ingly made it work. As soon as the code was minified, all the developer should be excited as well. I’m certain that An-
variable names changed and nothing worked anymore. gularJS 2 will be quite successful. I’m also certain that it
will be used in platforms other than just the browser. It
AngularJS 2 supports dependency injection too, but a better will help us build bigger and better applications, applica-
and improved version of it. As can be seen from Listing 8, tions that will scale better and perform better. I’m truly
there is no longer the magic string issue going on. You type excited about AngularJS 2, and I hope to talk a lot more
the name of the class as it appears, and you can choose to about it in future articles.
alias it using standard ES6 and TypeScript constructs. You
can then set a class variable in the constructor that can hold In the meanwhile, happy coding!
an instance of the provided service and use it appropriately.
This means that your code works the same in both mini- Sahil Malik
fied and un-minified scenarios. Your dev environment code
doesn’t break mysteriously when it’s thrown into production.
codemag.com AngularJS 2 21
ONLINE QUICK ID 1605051
major issues exist when attempting to use the control The Importance of Testing with Different Browsers
“out of the box” on a mobile device. In this article, I’ll and Devices
take you through those issues with a simple prescrip- The disparity between the desktop and mobile versions
tion that will help you avoid the struggles and pitfalls underscores the importance of testing. It never ceases
with this control. If you’re new to Web development or to amaze me how often developers certify that some-
have always relied on using third-party JavaScript and thing is working without at least some rudimentary test-
CSS frameworks as abstractions in lieu of working directly ing to verify that assertion. This extends to cases where
with base JavaScript and CSS, this article may prove to be something must work on a mobile device and such cer-
good learning resource for you. tifications are issued in spite of never having run the
John V. Petersen application on a mobile device! Too often, the assump-
tion is made that if it works on the desktop, it works
johnvpetersen@gmail.com
linkedin.com/in/johnvpetersen The Code on a mobile device. Often, that assumption holds true.
@johnvpetersen The code for this solution can be found on GitHub: Consider the fact that with mobile devices, there is no
https://github.com/johnvpetersen/HTML5AudioControl- mouse. You have to make sure that cases on the desktop
John is a graduate of the Rut-
gers University School of Law CodeMagazineArticle. The code is licensed under the MIT where you account for a mouse click are compatible with
in Camden, NJ and has been Open Source License. the finger gestures employed on a mobile device. Stated
admitted to the courts of the simply, if your team isn’t undertaking this sort of dili-
gence, they’re doing it wrong!
Commonwealth of Pennsylvania
and the state of New Jersey.
The Use Case
For over 20 years, John has Let’s say that you’re tasked to build a Web page that can
developed, architected, and de- play a number of audio clips. Features include: JavaScript and CSS to the Rescue
signed software for a variety of To fully illustrate how to make things work regardless
companies and industries. John • Start/stop of platform, I’ll use baseline JavaScript and CSS. That
is also a video course author for • Advance the clip means that there are no dependencies on additional
Lynda.com. HIs latest course, • Display clip’s progress frameworks and libraries. JavaScript frameworks and
Foundations of Programming, • Restart clip libraries can be valuable. However, it’s also important
Open Source Licensing, teaches • Identical UX for desktop and mobile devices to understand that such things are not always required.
everything you need to under- For purposes of this article, I want to focus on the Audio
stand about the legal aspects Figure 1 shows a mock-up of what these use-case re- Control itself and how to make it work with the basics.
of open-source licensing. quirements might look like. You also get to dispense with the Angular versus Knock-
out versus Ember versus whatever arguments. By going
this route, I know for certain that you can take this code
The HTML5 Audio Control Out of the Box and work with it regardless of whatever frameworks and
The following code illustrates a simple usage: libraries you’ve chosen.
<audio controls>
<source src="myclip.mp3" type="audio/mpeg">
Your browser does not support the audio element. It never ceases to amaze me
</source> how often developers certify
</audio> that something works without
at least some rudimentary
The HTML5 Audio Control has the capacity to alleviate a lot testing to verify that assertion.
of work. Not too long ago, there was legitimate concern over
whether all browsers supported HTML5. That concern has
not been totally alleviated. Looking to Figure 2, you can
see simple markup that is rendered in two very different
ways. The desktop browser version looks good. The iPhone Starting from the End: Our HTML
browser, Google Chrome in this case, is broken. The fact that The HTML, listed in Listing 1 for this solution, is very
it’s Chrome doesn’t matter. Safari doesn’t work either. simple and is illustrated in Figure 3.
The main point is that unless your Web application is limit- Unlike what you see in Figure 2 with the default Audio
ed to the desktop, which isn’t likely, the HTML5 Audio Con- Control display, you now have parity between desktop and
trol default visual features won’t prove to be very useful. mobile browsers. To make things manageable, I followed
Even in the desktop scenario, there’s no way to style the a simple convention:
visual appearance. The important takeaway is that for most
cases, the HTML5 Audio Control’s visual facilities are use- • Div id = X: This is the div that displays the play or
less. Fortunately, there’s a remedy with JavaScript and CSS! pause image, depending on the audio control’s state.
(function(d) {
})(document);
Figure2: Depending on your device, the HTML5 Audio Control with the Controls option set may not be functional.
Listing 2: ClipData that defines the title, artists and audio file sources
var clipData = { “title”: “Clip 2”,
“clips”: [{ “artist”: “Artist 2”,
“title”: “Clip 1”, “media”: {
“artist”: “Artist 1”, “src”: “SoundClips/clip2.mp3”,
“media”: { “type”: “audio/mpeg”
“src”: “SoundClips/clip1.mp3”, }
“type”: “audio/mpeg” }]
} }
}, {
The Template
Listing 3 illustrates the HTML template. I started with the out-
come, so Listing 1 illustrated the end-result of combining the
data in Listing 2 and the template in Listing 3. The process
of joining the data and template is shown in the next section.
Once the DOM has been hydrated, the process of wiring up the
event handlers can be initiated. Both the clipData and clipH-
Figure 3: Rendered display for the HTML in Listing 1. TML elements are processed in the createClipHTML() function.
Figure 5: Illustration of how the play and pause CSS classes are implemented
Why F#?
F# is a functional-first language on the .NET platform, which focuses on helping you solve complex problems with
simple, clean code. I’ll show you today how writing code that is similar to C#, and writing code that uses features
that are completely unique to F#, empowers you to create robust, maintainable solutions. Let’s get started!
Concise and Familiar Code You’ll notice first that the F# is somewhat shorter and
The ability to write clean and concise code that interop- lacking in punctuation, but that it’s otherwise quite com-
erates with all .NET languages is one of the most-cited parable. F# doesn’t need curly brackets or semicolons
favorite features of F#. It’s possible—and common—to because it’s whitespace-sensitive. For those of you who
use familiar .NET libraries from F#. Let’s compare two use, or have used, StyleCop, it’s like having some of that
very simple code samples that build a console app cre- functionality built right into the language!
ating a stopwatch calculating elapsed time. First, the
code in C#:
The previous function, square, is automatically updated Concise and Powerful Code
to be of type x:float -> float now, as will be any other F# has several features that let you succinctly model a
relevant code snippets because of the new information number of situations and lead you to write beautiful, de-
given to the compiler about these functions. clarative code. I’ll be covering discriminated unions, op-
tion types, and pattern matching in this article.
REPL
F# provides a REPL (Read-Eval-Print-Loop) to evaluate your Discriminated Unions and Pattern Matching
code easily. It’s a way to instantly evaluate your code with- If you’re unfamiliar with discriminated unions, you can
out compiling an entire project. You can either type code think of them in two ways. First, they’re similar to a C#
directly into the REPL, or, if you’re working in a script file, enum type. In the snippet below, I’ve declared a DateTi-
it’s simply a matter of highlighting the code you’d like to run meInfo that can be one of the six subtypes.
and choosing alt-enter (in Visual Studio) or control-enter
type DateTimeInfo =
| OrderDate
| PickDate
| ShipDate
| DeliveryDate
| CancelDate
| ReturnDate
// Get data
let wb = WorldBankData.GetDataContext()
[<Literal>]
let Path =
__SOURCE_DIRECTORY__ + “\example.json”
The main piece of code involves parsing the JSON for each
city, but first, you need to load the response by calling
Venues.Load.
let venues =
try
Some(Venues.Load(nearPlaceUrl + city))
with
| _ -> None
venues
F# is Fully Open-Sourced! contains thousands of sets of information for every |> Option.map (fun v -> v.Response.Groups)
country in the world. Freebase, the now-defunct on-
F# was completely open-sourced line database, also had a type provider; imagine an Next, you look for the group containing “recommended”
in 2010 and runs on many ORM trying to manage that scale! items, and ask for the first recommended item in that array.
platforms besides Windows. • Type providers also provide IntelliSense in the data
For information on learning, source, as you can see in Figure 4, which calls in to groups
teaching, or using F#, check out the World Bank type provider. For a database or csv |> Array.filter
the guides on the fsharp.org site,
file, you’ll see a list of table names and then column (fun g -> g.Name = “recommended” &&
the official home of the F#
names. For a Web service, you see a list of available g.Items.Length > 0)
Software Foundation
methods to call. |> Array.map (fun g -> g.Items)
|> Array.tryHead
these layout tools have advanced too, adding features want to use a custom set of colors; here’s how to make
that simplify commonplace layout problems. It’s these that happen. Start by creating a static class and add some
layouts that provide the means to building adaptive user static properties:
interfaces. In this article, I’ll look at the Xamarin.Forms
layout views and show how to use them to build various namespace Common {
UI design structures. static class Hues {
<Frame Padding=”30”>
<Label Text=”The Label” />
</Frame>
<Frame
Padding=”10,20”
BackgroundColor=”{x:Static c:Hues.Sky}”>
<BoxView
Color=”{x:Static c:Hues.Fire}”/>
</Frame>
It’s the same with the desired height. The desired height
will be taller when there are lots of characters, a big
font size, and word wrap are enabled. In general, it’s
better to let the view decide on its own size. You can
overrule the desired size if necessary by setting the Figure 2: The layout classes in Xamarin.Forms
ScrollView
ScrollView is useful when the child content is bigger than
can fit in the UI. For example, when the text content on
a page is too tall to fit on the screen, wrap the Label in
a ScrollView. This can make your UI readable on smaller
screen sizes. Content that fits on a big-screen phone like
the Nexus 6 will still be readable on the smaller Moto G
phone. This code snippet shows a tall BoxView within the
ScrollView:
<ScrollView
Padding=”30”
BackgroundColor=”{x:Static c:Hues.Sky}” >
<BoxView Figure 3: Default Size for BoxView on Android
Conclusion
Generally speaking, the Xamarin layout views follow a
similar structure to other XAML frameworks. They’re de-
signed to work in a cross-platform situation, which re-
sults in some unfamiliar territory for XAML veterans. Each
layout solves a specific problem. Once you understand
how each one works, you’ll find yourself layering them
together to build the UI of your dreams.
Walt Ritscher
it’s just a fact. Most training uses other editors and teach- The Single Layout Shell (w/o ASP.NET)
es you how to use HTML and JavaScript (Angular), period. I’m going to start by explaining and illustrating a tra-
But many of us are Microsoft developers and have a lot ditional Angular SPA. Keep in mind that I won’t be ex-
invested in the Microsoft stack, so we shouldn’t have to plaining what views and view-models are or how MVVM
turn away from it in order to jump on the Angular band- binding works. I’ll be assuming that anyone reading this
wagon. has Angular knowledge already, and later I’ll be making
the same assumption about ASP.NET MVC skills. By start-
If you start to look into typical Angular training, you’ll ing with a single layout SPA, and then building on my
Miguel Castro learn how to ditch Visual Studio, learn Web Storm and examples to show you how to handle a more complex site
miguelcastro67@gmail.com Node, and dive head first into the world of HTML and Ja- with more than one layout, I’ll be able to describe the
@miguelcastro67 vaScript without many—if any—other dependencies or problems I’ll solve later when I introduce ASP.NET MVC
additional technologies. This isn’t totally bad because if into the mix.
Whether playing on the lo-
you’re going to learn something like Angular, you do need
cal Radio Shack’s TRS-80 or
to learn it in full and understand all its parts intimately. A typical Angular-based SPA has an HTML view that sets
designing systems for clients
This article is not about that. This article won’t teach you up the layout of the website and a template placehold-
around the globe, Miguel has
been writing software since he Angular from the ground up. There’s a lot of great mate- er noted by the ng-view directive. This HTML page also
was 12 years old. He insists rial, both printed and digital about Angular and how to needs to load up any necessary JavaScript file, including,
on staying heavily involved work with it. This article is about showing you how to but not limited to, the Angular framework itself, the site’s
and up-to-date on all aspects leverage your ASP.NET MVC skills together with your An- module, and all required view-models. What I call view-
of software application design gular skills in order to have your cake and eat it too. Not models are, in fact, what Angular refers to as controllers.
and development, and projects only will I show you how to integrate the two technolo- Listing 1 shows you a sample Angular shell view called
that diversify into the type gies into a hybrid app, but I’ll also teach you my design Index.html. Notice that it uses an Angular module called
of training and consulting he and organization style that I use everywhere I have to appMain along with an Angular view-model called index-
provides to his customers. build these kinds of applications, including file location ViewModel. I refer to the Index.html view as the “shell
He believes that it’s never choices and coding conventions that I hope you’ll also view” because its content defines the shell layout for this
just about understanding the find beneficial. simple SPA site.
technologies but how technolo-
gies work together. In fact, it’s
on this concept that Miguel
bases his Pluralsight courses. Leverage your ASP.NET MVC What I call view-models are,
Miguel has been a Microsoft skills together with your in fact, what Angular refers
MVP since 2005 and when he’s to as controllers.
Angular skills in order to have
not consulting or training, he
speaks at conferences around your cake and eat it too.
the world, practices combining
on-stage tech and comedy, and
never misses a Formula 1 race. The layout for this site is very simple. It consists of a
But best of all, he’s the proud The Traditional SPA heading provided by the variable headingCaption, a
horizontal line, and some content beneath it. The content
father of a very tech-savvy
12-year-old girl. Frameworks like Angular, Ember, Backbone, and even swapped into the ng-view directive comes from various
Knockout are used to build something that’s become HTML templates, each binding to their own view-model.
known as a Single Page Application, or SPA. IMHO, this is And of course, this is all configured in the module setup
one of the most misused and dangerous terms I’ve seen using Angular’s routing capability, as shown in Listing 2
come around in a long time. You see, the sad truth is that along with the indexViewModel view-model that’s bound
many people take the terms they hear very literally, and in to this layout view in its <html> tag.
this case, they set out to write a Web application that is
indeed one single page with just a lot of view templates Basic Routing
swapped in and out of a placeholder. If the term SPA is to Each one of the HTML templates displays not only content
be taken literally and we all set out to write our Web ap- but also links that route to other views. These links are
plications in this fashion, things start out nice, pretty, and intercepted by the routes defined in Listing 2 and the
simple at first, but as the application grows, all hell can appropriate view and view-model is brought together and
break loose. Why would I say something like that? Well, replaced as the content in the ng-view placeholder. The
because literal SPAs have some limitations and can grow first route in the routing definition shows what view and
to be hard to manage, especially in a team environment. view-model is used when the routing path is a simple “/”,
Listing 5: CustomerIndex.html
<html data-ng-app=”appCustomer” data-ng-controller=”customerIndexViewModel”> <a href=”/ProductIndex.html” target=”_self”>
<head> Go to the product home page (link-based)
<title>{{ headingCaption }}</title> </a>
<link href=”Content/bootstrap.min.css” rel=”stylesheet” /> <br />
</head> <a href=”#” ng-click=”ProductHome()”>
<body> Go to the product home page
<h2>{{ headingCaption }}</h2> </a>
<hr /> </div>
<div class=”row”> <div class=”col-md-9”>
<div class=”col-md-3”> <div ng-view></div>
<a href=”/customer/list”> </div>
Go to customer list view </div>
</a>
<br /> <script src=”Scripts/angular.min.js”></script>
<a href=”/customer/detail”> <script src=”Scripts/angular-route.min.js”></script>
Go to customer detail view <script src=”Scripts/AppCustomer.js”></script>
</a> </body>
<br /> </html>
the previous examples, I referred to these views as shell Layout page. This pattern isn’t new and is core to any ASP.
views. This layout is rendered within the layout defined NET MVC application. The Layout page sets up the com-
for the site as a whole in the MVC Layout page. This is il- mon look and feel for the entire application. This means
lustrated in Figure 1. Once in a site section, we’re inside that it needs to define the static content that resides out-
a SPA and, for the most part, everything is the same as side of each SPA section. The Layout page in its entirety
the previous SPA examples I’ve shown you. I’ll go through can be seen in Listing 7. I refer to each SPA section as a
the order of operation starting with what is now the pri- SPA Silo, a term coined by my friend, author Brian Noyes.
mary shell of the entire Web application, the Layout page. Navigation links on the Layout page route to a conven-
tional MVC controller action, as in any other ASP.NET MVC
The Layout Page application.
In the previous example, I demonstrated how to set up
an application with two sections, each being its own SPA <ul class=”nav navbar-nav”>
and each having its separate Angular module, views, and <li>
view-models. However, you might recall that I was forced @Html.ActionLink(“Customers”,
to repeat some code in each of the shell views. Now I’ll “Customer”, “Home”)
work in an ASP.NET MVC application with Web API servic- </li>
es. This is a standard choice when creating a Web project <li>
in Visual Studio. My project will also have the AngularJS @Html.ActionLink(“Products”,
and Bootstrap NuGet packages installed. “Product”, “Home”)
</li>
I won’t be making any adjustments to the Global.asax or </ul>
the Web.config in the interest of simplicity, but if you use
my techniques, you’re free to add anything you need to The body of the Layout page can look however you want
your Web application, including a DI container, custom fil- and contain any static content you need. The placeholder
ters, or anything else. As in the prior example, this site will for the actual SPA Silo that makes up the section of the
have a Customer section and a Product section. The code site is a standard ASP.NET MVC RenderBody statement.
download that accompanies this article also includes an Or-
der section but in the interest of space, I won’t be covering <div class=”container body-content”>
it in the article. @RenderBody()
<hr />
The shell views, as I described them before, still exist, but <footer>
as CSHTML views. These views start by sharing a common <p>© @DateTime.Now.Year</p>
Next, I want a set of a global variables that contains the <body data-ng-app=”main”>
root URL to this application. This makes it easy to de-
ploy anywhere later without worrying about what the root This module is the only Angular module bootstrapped de-
address is. This problem rears its ugly head quite a bit claratively. Angular doesn’t allow more than one module
when you’re developing applications on your localhost to be assigned using data-ng-app, but it doesn’t mean
using a virtual directory, and then deploy to an actual that only one module is allowed. Later, you’ll see that
website where your applications sit at the root level. In this is the reason for the aforementioned jsCode section
many situations, you may need to refer to the root path of the Layout page. Also, if I wanted, I could also as-
of the application and having this variable handy makes sign an Angular view-model to the Layout page using the
that much easier. data-ng-controller directive. This gives my Layout page
the ability to benefit from binding to $scope variables
<script type=”text/javascript”> like any other Angular view. I’ve chosen, however, to keep
window.MyApp = {}; the Layout page simple and limit it to providing the static
MyApp.rootPath = ‘@Url.Content(“~”)’; shell layout design for the site and a place to put site-
</script> section navigation links, as I’ve already shown you. This
does bring me to the main Angular module. Because this
The root path of the application is easily obtained at the module is assigned here in the Layout page, the script file
server, so combining Razor syntax here with JavaScript that contains its definition is here as well. This is the App.
will work nicely. Remember, this view is being parsed and js file you saw earlier.
rendered by ASP.NET, so I’m free to include and leverage
any server-side power that I want. The creation of the The Site-Wide App.js and Index.cshtml View
MyApp namespace is so not to pollute JavaScript’s global Following the regular ASP.NET MVC order of operations,
namespace and avoid any potential conflict—although running my site would use the default MVC route {con-
the possibility of a conflict is minimal. troller}/{action}/{id}, and thus seek out a controller
class called HomeController and an action called Index.
Now I need to load up any additional scripts that the en- It’s entirely up to me to maintain this pattern or change it
tire site will use. to a different default route or a different default view. To
keep things simple, I’m maintaining the default pattern
<script src=”~/App/App.js”></script> and going with a default view called Index.cshtml.
The App.js file contains JavaScript code that’s available The App.js file I recently mentioned is used to contain
and leveraged to the entire application, meaning all SPA code used by the entire site, hence its declaration in the
Silos. I’ll go over its design and contents in detail later. Layout page. The location of this file is a folder called
Notice that this file resides in the App folder. This folder App. This is the pattern I’ve chosen for my MVC applica-
contains all of the Angular-related code for the entire ap- tion. The App folder itself contains this JavaScript file and
plication. You’ll see other App.js files in this same Web any others that are used by the site. Later, you’ll see the
application later, but their locations will be very different. sub-folder structure I’ll add in the App folder. This file
declares two modules that are very important. The first
The last two parts of the Layout page are code section Angular module declared is called common.
definitions. This is a feature that’s been used by traditional
MVC applications to render HTML code-parts but can also var commonModule =
be used for scripts. I’ve added two sections, both non- angular.module(‘common’, [‘ngRoute’]);
required.
This module won’t be attached to any view directly. I
@RenderSection(“scripts”, required: false) use it as a place to hang shared services from and also
<script type=”text/javascript”> as a place to inherit other modules from, as in this case,
@RenderSection(“jsCode”, required: false) ngRoute. You might have noticed the ngRoute module
</script> in previous code examples. It’s declared in the Angular
script and is necessary for routing to function properly.
The first, called scripts, will be used by the view that gets Adding other Angular services to my site will become
rendered by the RenderBody statement to contain any easier now, because I just need to add them to the in-
heritance array in the common module declaration. The above syntax, the name of the module as attached to the
App.js file also declares a shared service called view- Layout page is main, but the variable that represents the
ModelHelper. Its contents are beyond the scope of this module for procedural code is mainModule.
article, but it’s included in its entirety with the accom-
panying code download. I declare the viewModelHelper The Index.cshtml view that comes up by default (based
service by using the factory method from the common on the default MVC route) when the site runs is bound
module. to an Angular view-model called indexViewModel. This
view-model is also declared in this App.js file and it
commonModule.factory(‘viewModelHelper’, hangs off of the main module.
function ($http, $q, $window, $location) {
return MyApp.viewModelHelper( mainModule.controller(“indexViewModel”,
$http, $q, $window, $location); function (
}); $scope, $http, $q, $routeParams, $window,
$location, viewModelHelper) {
Then, I simply create the viewModelHelper function.
var self = this;
(function (myApp) {
var viewModelHelper = function ( $scope.topic =
$http, $q, $window, $location) { “Integrating ASP.NET MVC and AngularJS”;
$scope.author = “Miguel A. Castro”;
var self = this; });
// function members go here In the case of this view, the currently bootstrapped An-
gular module is main because it was attached in the
Layout page. The services I’m injecting into this view-
return this; model are the common ones that I inject into all my
}; view-models, although I’m not really using any of them
myApp.viewModelHelper = viewModelHelper; here except $scope. Notice the injection of the view-
}(window.MyApp)); ModelHelper service as well. The Index.cshtml view can
be seen in Listing 8, where you can see me use the
Notice that I’m using the myApp namespace I declared topic and author variables as they are declared in the
back in the Layout page. As I stated earlier, this is to view-model.
avoid polluting the global namespace.
Clicking on the site heading of the Layout page routes you
Having the common module makes it easy for the main to the Index.cshtml view from anywhere in the site in
module and all other Angular modules going forward to the conventional MVC fashion. Clicking on any of the links
inherit functionality that I need across the entire site, be- for Customer or Product calls upon the Home Control-
cause all they have to inherit from in order to gain such ler’s Customer or Product action methods. These actions
functionality is the common module. The declaration of are designed to render the Customer.cshtml or Product.
the main module does just that. cshtml MVC views respectively. These views are the root
views for the Customer and Product SPA Silos.
var mainModule = angular.module(
‘main’, [‘common’]); The SPA Root Views
The standard MVC route {controller}/{action}/{id} al-
This module is attached to the Layout page’s <body> tag, lows me to route to Home/Customer or Home/Product
as you saw earlier, and because it inherits from the com- and get to the Customer.cshtml and Product.cshtml
mon module, it also inherits from the ngRoute module views. Later, I’ll alter these routes, but for now, I’ll con-
and the declaration of the viewModelHelper shared ser- tinue based on the fact that it was the default route
vice. Using this service in a controller now is as easy as table entry that got me to these views. For the purposes
injecting it by using its name. Note that, as noted in the of the example going forward, I’ll stick to the Customer
Because this view is the root view for a SPA Silo, the Cus-
tomer SPA Silo, it uses a separate Angular module along
with its own set of Angular view-models. The JavaScript
files that contain all of this information are loaded in the
scripts section of this view. Remember, this view is loaded
by ASP.NET MVC, meaning that I have all the power of the
server-side Razor engine at my disposal. The scripts sec- Figure 3: Hybrid App Folder Structure
tion is combined with the Layout page where the section
was defined.
SPA Silo, and a Views folder that contains the HTML
@section scripts { templates. The files in these two folders have a one-to-
<script src=”~/App/Customer/App.js”> one correspondence with one another and their naming
</script> differs only in their suffixes, ViewModel and View. Ad-
<script src=”~/App/Customer/ViewModels/ ditional sub-folders can include scripts and content as
RootViewModel.js”> well. Given this convention, my site’s App folder looks
</script> like Figure 3.
<script src=”~/App/Customer/ViewModels/
CustomerHomeViewModel.js”> In reference to the recent code-snippet, where I show
</script> you the “scripts” section, notice that I’m loading four
<script src=”~/App/Customer/ViewModels/ view-models. The one declared in the RootViewModel.
CustomerListViewModel.js”> js file is the view-model that applies to this root view.
</script>
<script src=”~/App/Customer/ViewModels/ This view needs to bind to its own Angular module. The
CustomerViewModel.js”> reason for this is primarily to isolate the view-models,
</script> services, and routes that will be handled within this
} section. It also makes things much more manageable.
The module, to be called customer, cannot however be
You may recall me mentioning that there will be other attached using data-ng-app. That directive can only
App.js files later. You can see one here, but notice its be used once per current rendering, and if you recall,
location. This is key to the naming convention I use. I used it in the <body> tag of the Layout page to at-
Because I declared this to be the Customer section of tach the main module. I can, however, load and attach
my site, I have a Customer folder under the App folder. it procedurally, and that is what the jsCode script sec-
The App.js file in this folder accommodates everything tion is for.
for the Customer section only, whereas the App.js that
is one level up in the App folder accommodates all sec- @section jsCode {
tions. angular.bootstrap(
document.getElementById(“customer”),
The Customer folder under the App folder is an example [‘customer’]);
of the folder structure I use throughout my entire site. }
The sub-folders immediately beneath the App folder
each represent a site section. I use the same name as Here, I’m telling Angular to attach the customer module
the action method in the HomeController MVC control- (in the square brackets) to the element with the name
ler class that navigated me to this section. Under these customer (in the parentheses).
sub-folders, I have the SPA Silo’s App.js file, which I’ve
just described. I also have sub-folders for everything The body of the view is wrapped in a div tag marked with
else that deals with this particular SPA Silo. These sub- the Angular ng-non-bindable directive.
folders include, but are not limited, to a ViewModels
folder that contains the Angular view-models for this <div ng-non-bindable>
<div id=”customer”
data-ng-controller=”rootViewModel”>
I’m also binding this tag and all its content to the root-
ViewModel Angular view-model.
var customerModule =
angular.module(‘customer’, [‘common’]);
customerModule.config(function
($routeProvider,
$locationProvider) {
$routeProvider.when(‘/customer’, {
templateUrl: ‘/App/Customer/Views/
CustomerHomeView.html’,
controller: ‘customerHomeViewModel’
});
$routeProvider.when(‘/customer/list’, {
Each SPA Silo needs a similar MVC route entered into the
routing table.
routes.MapRoute(
name: “product”,
url: “product/{*catch-all}”,
defaults: new {
controller = “Home”,
action = “Product” });
also create maintenance nightmares for the future. In this details. The properties associated with the cell are as-
article, you will learn how to tame these monsters. I’ll signed inside the function. In the future, you might be
start with an app that consists of a massive controller and interested in displaying some additional properties on
work my way toward a leaner implementation. the user interface. This means that you’ll assign more
cell properties inside the cellForRowAtIndexPath func-
The basic principle behind lean controllers is the single tion, hence polluting it with unnecessary code, as indi-
responsibility principle. This means that every component cated in Listing 2.
of the application should have a single job and purpose.
By isolating each component to perform a single task, you
Mohammad Azam make sure that the code remains lean and easy to maintain.
The concepts and techniques
azamsharp@gmail.com
www.azamsharp.com learned in this article can be
@azamsharp Scenario applied to any iOS application
Mohammad Azam works as a
The iOS application under discussion is a simple user regardless of the data access
Senior Mobile Developer at task-management app. The application consists of a sin- layer used.
Blinds.com. He’s been develop- gle screen where the user can add tasks to a list. Users
ing iOS applications since can delete the tasks by swiping right to left on the row
2010 and has worked on more and then pressing the delete button. The user can mark
applications than he can the tasks as complete by selecting the cell using a single The best way to deal with this problem is to refactor the
remember. Azam’s current app, tap gesture. All of the tasks are persisted in the SQLITE configuration of the cell into a separate function. Luckily,
Vegetable Tree - Gardening database using the FMDB wrapper. The screenshots of the the TaskTableViewCell is a perfect candidate to define such
Guide, is considered the best app running in action is shown in Figure 1 and Figure 2. a function. The implementation of the configureCell func-
vegetable gardening app on the tion is shown here:
app store and was featured by In the first section, you’ll inspect the TasksTableViewCon-
Apple in 2013. He’s a frequent troller implementation, which orchestrates the complete func configure(task :Task) {
speaker at Houston Tech Fest flow of the application. You’ll quickly realize that the im-
and Houston iPhone Meetup. plemented code is not reusable and is hard to maintain. self.titleLabel.text = task.title
When not programming, Azam You’ll take the whole application apart and create reus- self.shortTitle.text = task.shortTitle
likes to spend his time with his able, single-responsibility components that protect the self.imageURL = task.imageURL
beautiful family and planning application for future changes. }
for his next trip to the unknown
corners of the world.
The configure function accepts a Task model object and
Implementing a Lean View Controller then populates the cell properties based on the prop-
The best place to start is the viewDidLoad event of the erties of the model. The next snippet shows the call to
TasksTableViewController. The viewDidLoad event is in- the configure function inside the cellForRowAtIndexPath
voked each time the app runs. Inside the viewDidLoad event.
event, you trigger the initializeDatabase function. The
initializeDatabase function is responsible for copying the override func tableView(tableView:
database from the application bundle to the documents UITableView, cellForRowAtIndexPath
directory of the application. Because this procedure indexPath: NSIndexPath)
needs to be performed only once for each app, there’s no -> UITableViewCell {
need to call it from the viewDidLoad event. You’re going
to move the initializeDatabase function into AppDelegate guard let cell = tableView.
where it can be called from within the didFinishLaunch- dequeueReusableCellWithIdentifier
ingWithOptions event. By moving the initializeDatabase (“TaskTableViewCell”, forIndexPath: indexPath)
call inside the didFinishLaunchingWithOptions, you’ve as? TaskTableViewCell else {
made sure that initializeDatabase is called only once dur- fatalError(“TaskCell not found”)
ing the lifecycle of the application. Listing 1 shows the }
implementation of the initializeDatabase function.
let task = self.tasks[indexPath.row]
Next, move to the cellForRowAtIndexPath function. At cell.configure(task)
first glance, the cellForRowAtIndexPath implementation return cell
doesn’t show any warning signs, but the devil’s in the }
db.open()
defer {
let result = db.executeQuery(“select * from tasks”, db.close()
withArgumentsInArray: []) }
tions to protocol functions. Currently, the TasksTableView- completed and uncompleted tasks. The implementation is
Controller contains a lot of code that deals with the look shown in the following snippet. SPONSORED SIDEBAR:
and feel of the UITableView control. This includes the
Need Help?
implementations for didSelectRowAtIndexPath and com- func configure(task :Task) {
mitEditingStyle events. By providing an extension to the self.titleLabel.text = task.title Looking for help optimizing
TasksTableViewController, you can move a lot of clutter if(task.isCompleted) { your application architecture
from the TasksTableViewController class to the extension. self.titleLabel and design application? The
.attributedText = task.title.strikeThrough() experts at CODE Consulting
} else { are here to help with your
self.titleLabel project needs! CODE has a
FMDB is a thin Objective-C .attributedText = task.title.removeStrikeThrough() 20-Hour Introductory Service.
open source wrapper on } Get full access to a CODE
top of the SQLite database } team member for 20 hours
that provides a lot of helper to have them help you on
methods for performing Run the app again and now you’ll notice that the strike your project. Use this time for
through rows persists while scrolling the UITableView one-on-one mentoring, give
database operations from your project the push it needs
control!
within your applications. to get started, or anything in
between! Hours can be used
Conclusion consecutively or divided up
as needed.
The great thing about extending the TasksTableViewCon- Implementing lean controllers takes more effort than Email info@codemag.com
troller using protocol extensions is that it will have access writing massive controllers. It might be tempting to put to set up your time with a
to all of the properties defined in the TasksTableViewCon- all the code into one controller, but keep in mind that CODE specialist!
troller implementation. The implementation of the did- although you might move fast initially, you’ll quickly hit
SelectRowAtIndexPath defined inside the TasksTableView- a wall. It’s always better to refactor and move toward a
Controller extension is shown in Listing 6. more solid design initially when things are in motion,
rather than waiting until the components have been fixed
You’ll also notice that I’ve used an extension method for into place.
String type to create the strikeThrough effect. This allows
you to reuse the strikeThrough function in other parts of Mohammad Azam
the application.
the last eight years (from SSRS 2008 to the present)- been writing articles as test or interview questions, and
thereby empowering SSRS advocates to make a stronger this article will also diverge in that I’m only covering the
and more compelling case that SSRS is indeed a prime- following eight items:
time player in the world of business reporting. In this ar-
ticle, I’ll demonstrate some tips and reusable approaches 1. Implementing column level security in reports
in different areas of report authoring/generation that 2. Implementing drilldown functionality with options
help make that case. to set initial drilldown
3. Creating cross-chart filter refresh effects
4. Repeating column headings across multiple pages
Kevin S. Goff SQL Server Reporting Services: 5. Dealing with page margins and blank extra pages
kgoff@kevinsgoff.net The Ultimate Bread and Butter 6. Relating multiple tables in a report
http://www.KevinSGoff.net of Reporting Tools 7. Implementing a nested “Page X of Y” on a report
@KevinSGoff Recently, I heard someone say, “Third-party report and 8. Implementing Running Aggregations in a report
charting tools might have many bells and whistles, but
Kevin S. Goff is a Microsoft SQL
Server MVP. He is a database SQL Server Reporting Services is still the bread and butter I’ll present many of these tips by saying, “You want to im-
architect/developer/speaker/ for many developers.” plement functionality/behavior ABC, but you’re running
author, and has been writing into a limitation. Is there a solution or workaround?” This
for CODE Magazine since 2004. From the late 1990s to 2007, I was a die-hard Crystal reflects many scenarios that I encounter in my consulting
He’s a frequent speaker at Reports fanatic and published a book on Crystal Reports practice.
community events in the mid- development with .NET. Toward the end of that period, I
Atlantic region and also speaks took a serious look at SQL Server Reporting Services 2005 Tip #1: Implementing Column-Level Security in Reports
regularly for the VS Live/Live (I’ll use the acronym SSRS for the rest of this article). I Suppose you build a report that both regular users and
360 Conference brand. He cre- concluded that SSRS 2005 was a good but not outstand- executives will view. In addition to other data, the report
ates custom webcasts on SQL/ ing product, and lacked functionality compared to Crystal contains cost and profitability measures that only execu-
BI topics on his website. Reports. That changed in SSRS 2008. Microsoft didn’t try tives should see. The regular users should only see speci-
to match every single bell and whistle of Crystal Reports fied data and the space for the cost columns shouldn’t
in SSRS 2008; instead, they expanded their existing re- appear. Users should see the report as if the cost and
porting (and charting) functionality on their own terms, financial measures never existed. Does SSRS provide secu-
and greatly improved the scalability and performance of rity features to hide columns based on domain accounts/
the reporting engine. groups?
So instead of adding the bells and whistles, Microsoft The answer is that SSRS doesn’t provide any built-in func-
fortified their bread and butter. Although Crystal Reports tionality to address column-level security. However, just
still had an edge on the total number of features, SSRS like many developer products, SSRS doesn’t stand in your
2008 became a truly viable option for internal business way from manually implementing such functionality.
reporting. Microsoft continued to expand SSRS in SSRS
2008R2, and has given certain UI areas of the product
a much-needed make-over in the upcoming SQL Server
2016 release. Just like many developer
products, SSRS doesn’t stand
Still, SSRS suffers from a bit of a perception issue. To in your way from manually
many, SSRS remains merely adequate, but lacks some of implementing column-level
the power found in third-party tools, competing products, security functionality.
and even the quasi-reporting capabilities in Excel. One of
my roles as a consultant is to show developers and manag-
ers the full power of SSRS and how experienced developers
can extend it. Several of the tips in this article reflect those I’ll keep the example very simple and will focus on the
exercises to demonstrate the power of the product. mechanics. Figure 1 shows a very basic report, with a
column (“Modified Date”) that you want to configure for
visibility based on the current user.
What’s on the Menu?
For over a decade, I’ve been using the Baker’s Dozen You can implement this in five steps. Essentially, you’ll
theme of giving you 13 tips. In the last year, I’ve even create a SQL Server table to define user/column visibility,
I’m on a Mission.
I admit it.-I’m on a mission. That
mission is to show developers
and managers what SSRS can do.
Although no tool can accomplish
every imaginable task, SSRS
remains a powerful “bread and
butter tool” that you can often
extend. It might require some
elbow grease and the end
result might not win any beauty
awards-but often the result will
be good enough. Figure 5: An internal SSRS parameter that will hold the value for the column visibility
I’ll throw in a pop-culture reference here. Do you remem- Let’s stop and reflect that
ber the old TV show, “Name that Tune?” The signature you’ve used hidden/internal
response in that show was: “I can name that tune in (N)
parameters as a means to
notes.” Well, I can sing the “cross-chart filter visualiza-
tion” in three steps. Essentially, you’ll tap into the SSRS drive different SSRS behaviors.
Report Action feature for a plotted data series point, and
re-launch the report. As you do that, you’ll pass forward
to the report a hidden parameter for the year/country Having said all of that, here are the three steps:
Figure 8: Using the SSRS Group Properties to define the visibility and the report element that toggles the display of
that group
Figure 10: The report page after the user clicks on U.K. Sales in 2013 on the left
SSRS keeps track of the current country/year series when that you’re implementing some SSRS design patterns
you click on a specific series. here, ones that could be used for other report functions.
Step 3: For each chart, go to the Series Properties dialog Tip #4: Repeating Column Headings Across Multiple Pages
box and the Fill tab (Figure 12). Set the Color Expression to Even the best tools in the world have an Achilles heel,
yellow if the current year and country that SSRS is plotting and this topic represents a very strange issue and even
happens to be the same value in the HotSelect parameter. stranger workaround in SSRS.
Before you go any further, let’s stop and reflect that Suppose you implement a standard tabular report (i.e., a
you’ve used hidden/internal parameters as a means to fixed number of columns) that spans many pages. When
drive different SSRS behavior. It’s not a stretch to say the user views the report in a browser and navigates be-
Figure 12: Setting the Report Series fill color based on whether the current plotted country/
year matches the hidden parameter
Figure 13: Click the drop-down to the right of Column Groups to enter Advanced Mode Figure 14: SSRS Advanced Mode with Static Row Groups
Figure 20: An example report that shows running totals, running averages, and running At first glance, you might think that SSRS provides three
maximum values (highest month to date) separate functions for the three columns. As it turns out,
May/June 2016
Volume 17 Issue 3
Group Publisher
Markus Egger
Associate Publisher
Rick Strahl
Figure 21: RunningValue function with parameters
Editor-in-Chief
Rod Paddock
Managing Editor
SSRS provides just one function, called Run- Final thoughts: Ellen Whitney
ningValue. You provide the aggregation method I hope I’ve provided some information to help
Content Editor
as a parameter to the RunningValue function. you in building SSRS reports. In future articles, Melanie Spiller
Figure 21 shows an example. I’ll continue to show different SSRS power tips.
Writers In This Issue
As a SQL Server/Business Intelligence contrac- Mohammad Azam Jason Bender
You pass three parameters to RunningValue: tor/consultant, I’ve always found that working Miguel Castro Kevin Goff
near the report layer helps me to understand the Sahil Malik Ted Neward
John Petersen Rachel Reese
• The column value you wish to aggregate breadth and depth of the client’s business appli- Walter Ritscher Paul Sheriff
(the Monthly sales amount) cation. Users will always want functionality that Technical Reviewers
• The aggregation method (Sum, Avg, Max, the product doesn’t provide out of the box, so Markus Egger
etc.). Note that SSRS color-codes the ag- the value of SSRS depends on whether the tool Rod Paddock
gregation method in blue, indicating that provides enough hooks or open architecture for Art & Layout
SSRS treats it as a keyword. developers to extend it. Overall, SSRS does a very King Laurin GmbH
info@raffeiner.bz.it
• The scope of the aggregation (the name of good job here.
the group). In this instance, you’re aggre- Production
Franz Wimmer
gating months within a year. Every running Kevin S. Goff King Laurin GmbH
aggregation contains a scope, so you need 39057 St. Michael/Eppan, Italy
to provide the actual SSRS group name. Printing
Fry Communications, Inc.
800 West Church Rd.
Mechanicsburg, PA 17055
Advertising Sales
On Responsibility
For an industry that prides itself on its analytical ability and abstract mental processing, we often don’t
do a great job applying that mental skill to the most important element of the programmer’s tool
chest—ourselves.
Over the last year or so, I’ve been writing a lot Relational databases have been doing this for “Just Following Orders”
about management and related topics. But two years: A number of different benchmark tools, Programmers must build what they are told to
incidents in the last several months have finally called the TPC-A (through -E) benchmarks, are build. We are, after all, performing “work for
pushed me over the edge into getting back to a routinely run against the various RDBMS ven- hire,” most of us, and in the same vein that we
topic that is closer to the individual developer dors’ products to determine relative performance garner no benefit (in the form of profits, royal-
again. The first is the (as of this writing) ongo- numbers. And, as the story goes, database ven- ties, license payments, or some other money)
ing saga around the San Bernardino shooter’s dors cheat outrageously inside their databases in from having written the software, neither can we
iPhone, and the US court order demanding that order to optimize specifically to those use cases, therefore be held responsible for its effects.
Apple comply with the FBI request for assistance thereby distorting the actual numbers in order to
in breaking into the device to retrieve informa- return faster (and therefore presumably better) In many ways, this is the same argument used at
tion from it that the FBI deems useful and/or numbers against their competitors. the Nuremburg Trials against the various members
necessary to the investigation. The second is the of the German Army and SS for their crimes against
ongoing saga around the Volkswagen emissions This raises an interesting ethical question: If a humanity. In a military hierarchy, if a superior of-
benchmark “hack” that changed the engine’s software developer is asked to implement a fea- ficer gives you an order, you’re compelled to obey
performance characteristics. This was based on ture that either leads to, or is, or is itself di- it or face court-martial. That means, of course, the
information fed to the emissions benchmark from rectly unethical, immoral, or illegal behavior, is officer who gave that order holds the responsibility
the sensors elsewhere in the car so that when the that software developer liable for the damages for its effects, but as the individual who carried it
vehicle was being tested for noxious emissions, caused? out, you are immune from its effects.
it operated in a less-performant but eco-friendly
way, and otherwise pumped out much higher tox-
ins than allowed by various national environmen- Ethics, Not Legalities The Last Responsible Moment
tal standards (including both Germany’s and the Just to be clear, the argument I want to have But the “following orders” argument holds signifi-
US’s). here is based around the morals and/or ethics of cant flaws: One is that, except for those program-
the issue, not its legalities. The reason for this is mers who are a part of the armed forces, we aren’t
In each of these cases, software lies at the heart manifold: To start, the classic IANAL (I am not a in a strict hierarchy, and there are no legal conse-
of the story. But my concern is this: To what de- lawyer) disclaimer is in full force here, and I de- quences from disobeying a superior. If instructed
gree are software developers responsible for their fer any and all questions of the law to my friend to implement a feature that you find unethical,
actions in each case; to what degree will we be and colleague, John V. Petersen, who also writes immoral, or illegal, you are certainly capable of
held responsible by the legal framework in which in this publication and may be so moved as to refusing to do so, and many in the industry would
we live (be that in the US or elsewhere); and to take up this question in a future issue. Secondly, applaud you for it. You’d be unemployed, granted,
what degree should we hold ourselves respon- though, is the simple fact that laws change with but you wouldn’t be the one responsible—legally or
sible? the times—the question of slavery in the US being otherwise—for said feature. Somebody else might,
just but one extreme example—and so what holds who can’t really afford to be unemployed for any
as legal today, may not be so tomorrow or vice length of time, but that’s their problem, not yours.
Background versa. It is fully safe, I believe, to assume that
Although it would be easier to debate or discuss the laws around software and liability will change Perhaps the right way to think about this is in the
if readers have a relatively basic understanding of as the role, nature, and responsibility of software same way we think about technical decisions—
each situation, each one can be abstracted away increases in our daily lives. that the individual who has the last responsible
from the details pretty easily. moment before an incident occurs is the one to
This is not without precedent—in the earliest days whom we assign responsibility. Thus, since you
In the VW case, software engineers were instruct- of the Industrial Revolution, no laws around ma- are the one who wrote the code, you are the one
ed by management—and as of right now, it’s not chine safety, even for food production, were in responsible for it, irrespective of what your boss
clear exactly from where those orders came, but place. As the impact of industrial processing grew, or management chain demanded.
popular perception holds that it definitely “came however, and abuses grew (particularly against
from above,” rather than originating with one of those who worked the machines—read Upton This is not without precedent—in the US, many
the engineers themselves—to deliberately change Sinclair for more graphic details), legal frame- states have a similar concept in place around the
the operation of the vehicle under particular con- works were established and liabilities enforced. application of fault in a driving accident. If one
ditions. Whether the engineers understood that One might argue that the pendulum has swung driver had an opportunity to avoid the accident
those conditions were the ones that would more too much the other way by this point, and an- and didn’t take it (for whatever reason), that driv-
than likely identify the vehicle as being tested for other might argue the reverse and that still more er is at fault regardless of the actions or behavior
emissions standards is not entirely clear to me, protections are necessary, but either way, the fact
but this is not new ground for us as an industry. remains that laws change. (Continued on page 73)