text:
Earlier this year I wrote a blog post about JavaScript and why I thought it was doomed; I also wrote a blog post about responsive design and why I thought it was a waste of time.
To be fair, I didn't completely bash either technology, but I also didn't have very many kind words to say about JavaScript or responsive design either.
It turns out that shortly after writing those articles, I found myself, ironically, working much more with JavaScript and having to use websites from my mobile device that were not created with responsive design techniques.
I consider myself to be pretty open-minded, especially when it comes to technology, but in both of these cases, I was being a bit narrow-minded and I think it is important to be willing to admit when you are wrong.
First let's talk about JavaScript
Dear JavaScript, I'm sorry I said that you were ugly and that you would die soon. I realize that you might not be the most attractive programming language ever created, but like troll dolls or the furby, you have a special kind of beauty that I've since learned to appreciate. And, as for predicting your death, well, it does seem that you are still in the prime of your life, and while everything eventually dies, even programming languages, it isn't nice to remind people of their mortality. So, for both of those offenses, I am truly sorry.
On a more serious note, it seems that pretty soon after writing up that article I ended up creating several Pluralsight courses in which I was doing quite a bit of JavaScript development.
By doing this, I actually discovered that the ubiquity of JavaScript was actually very valuable and that it wasn't as hard as I imagined to create fairly complex JavaScript based applications.
Let me explain a bit further.
After having created several applications using several different platforms and technologies with JavaScript, it became clear to me that the language itself was very flexible and JavaScript's ability to easily treat data like code, through the use of JSON, was very useful.
At first, when I was just creating web applications with JavaScript, using it as a scripting language to do UI automation, this flexibility seemed to get in the way and make things more complicated than I liked. I still think that JavaScript can be quite messy in a traditional web application that posts back to the server.
But, when I started using JavaScript to create Chrome plugins, and develop Single Page Applications, this flexibility became extremely useful, because I could basically create exactly what I wanted without a bunch of ceremony around it. I started to see JavaScript as something I could use to build a more specific API that was specific to the problem domain I was solving. I also saw that in many cases, for example Meteor, someone else was already doing this for me and I could just follow the conventions they laid out.
I still think there are some things about JavaScript that need to be improved. But, overall, I have learned to stick to the good parts as much as possible. More importantly, I have learned that knowing the core concepts of JavaScript and programming with JavaScript has allowed me to build a good base which I can bring to many different platforms and environments. Even though different programming environments may define their own conventions for using JavaScript to create an application or extend one, it is relatively easy to adapt to those conventions once you are familiar with some of the core parts of JavaScript that carryover everywhere.
I also have grown to like the prototypical nature of JavaScript and other prototypical languages like Lua. I've always been a big fan of statically typed languages, and I still am, but I can also now appreciate some of the patterns that only a prototypical language allows which can really allow you to do quite a bit with just a little code.
Onto responsive design
I actually had a very enlightening conversation with a gentleman on Twitter, who really helped me take a second look at responsive design and why it was more useful than I thought.
One of the biggest ways that he shifted my thinking about responsive design was by helping me to realize that it isn't just PC, mobile phone, tablet, but that there were all kinds of forms factors and kinds of devices that a web page should look good and function well on today.
It also seems that right after I had written that article that I ended up having to use my phone for doing web based things much more than I had before then. I quickly became frustrated with websites that did not implement some kind of responsive design and found myself smiling when I happened upon a website that was mobile friendly and altered the UI to make it much easier to use on a phone.
When I thought about it more, it turned out that I was responding instinctively to the fad of responsive design, but not realizing the actual value that was there. I probably have a tendency to backlash hard against technology trends that seem to be fads or trendy. Sometimes, I do get a bit overzealous in doing so and don't realize that even though many people are ignorantly worshipping some new technology or trend, there are many others who are wearing the latest techno-fashion, because it really is good and useful.
By the way, I found this book, to be a good resource for learning about responsive web design, if you are looking to get a bit more understanding of it.
I still don't think it is healthy or smart to jump all into responsive design without a good reason for doing so or having a good understanding of the value it will bring. (Responsive design is not for everyone.) But, I do think responsive design is a good solution and should be implemented in many more cases than what I had originally thought. I can see a large amount of value in making an existing site responsive, because it can attract more business and make it easier for existing customers to give you money or use your product.
I even find myself wishing that my website was more responsive. This blog has a default mobile theme, but I am wondering how much mobile traffic I am losing out on, or how many opportunities to convert that traffic to customers to one of my products I am also missing out on, because I am not presenting the information on this blog in the best way I can for a smaller device.
A good lesson
It turns out being wrong about these two technologies was a good lesson for me, because it helped me realize that even though I like to think that I have eliminated most of my technology biases, there are still plenty that exist.
One of the key things that I've always said about this blog is that I am not going to stop from saying something because I am not 100% sure of what I am saying. What I mean by this is that I will give my view to the best of my knowledge, but that view is subject to revision. There really is no need to hold onto a viewpoint that is wrong, once you realize it is wrong and it is ok to be wrong sometimes. We all have to be willing to grow and learn along our journey. If we want to be able to improve, we have to be willing to allow ourselves to be wrong and to be ok with that.
There are so many posts that I have written for this blog that I wouldn't agree with 100% today and that is because my knowledge and experience is changing. I really wouldn't want it any other way. If I agree 100% with what I wrote about last year or the year before, I would be 100% the same person I was back then, so I wouldn't be growing and improving. I'd rather be wrong sometimes and grow than think I am right all the time and stagnate.
Creating an Automated Testing Framework With Selenium
I have another new course on Pluralsight, check out:
Creating an Automated Testing Framework With Selenium
I am very excited to finally get this course out. Many viewers have been asking me to make a comprehensive course that actually shows you how to build a real automation framework, and I finally did it in this course.
I reveal all my tricks and tips here and tell you exactly what I have done in the past to build successful automation frameworks. It was a lot of fun to create this course and it brought me back to the glory days of creating automated tests. (This is some serious fun!)
Anyway, check out the course and let me know what you think.
Here is the official course description:
Learning how to use a tool like Selenium to create automated tests is not enough to be successful with an automation effort. You also need to know how to build an automation framework that can support creating tests that are not so fragile that they constantly break. This is the real key to success in any automation effort.
In this course, I will reveal every secret I know from creating several successful automation frameworks and consulting on the creation of others. I will show you exactly, step-by-step how to create your own automation framework and I will explain to you the reasoning behind everything we are doing, so you can apply what you learn to your own framework.
We'll start off this course by going over the basics of automation and talking about why it is so important as well as discuss some of the common reasons for success and failure.
Then, I'll take you into the architecture of an automation framework and show you why you need to pay careful attention to the structure of any framework you build and give you some of the underlying design principles I use when creating an automation framework.
After that we'll be ready to start creating a framework. In the next few modules, I'll show you how to create a real automation framework capable of automating the WordPress blogging platform administrative console. We'll start off by creating smoke tests and using those smoke tests to build out our initial framework.
Then, we'll expand the capabilities of our framework as we create more tests and learn how to use techniques like dummy data generators to make our tests as simple and easy to read as possible.
Finally, I'll take you through some best practices and tips that cover topics like scaling out, working in Agile environments and other important issues you are likely to face. If you are responsible for an automation project for a web application or you want to start using automation, you'll definitely want to check this course out.
How Religion Destroys Programmers
I discovered something about myself—I have an amazing gift to always make the very best technology choice.
No really, it is quite amazing.
When I look back at my development career, it seems to me that every programming language I was using at any given time was clearly the best one.
The same goes for frameworks and even operating systems.
Yes, I have this amazing ability to pick from the vast ocean of technologies, without even trying them all out, the very best one, and to vehemently defend my choice.
Perhaps as you've been reading this, you've discovered you have this uncanny ability as well?
Most developers are religious about technology
It's true.
Don't be ashamed, you are not alone. Myself, and just about everyone else, is with you.
Some of use are recovering from our self-imposed brain washing. Others of us are blissfully unaware of our predicament. But most of us have at least one religion we've managed to craft ourselves.
It is perfectly natural because most programmers got into the field of software development because they were passionate about it. Anything you are passionate about is likely to cause you to develop some highly charged opinions.
Take sports fans for instance. I'm not really much of a sports fan myself, but I know many fans of all different kinds of sports that religiously believe their team is the best despite all the evidence to the contrary.
This defense of our own choices and ideas is core to human nature. It is easy for us to adopt a new idea but we religiously defend the ones we have without needing much evidence to back it up. The problem is we tend to tie up our ideas about things with our identity and even our value as human beings.
It takes some deep soul searching, but it you look within yourself you'll probably find that you can make a list of the best operating systems, programming languages, frameworks and so on.
Ignorance is not bliss
The problem with this self-imposed religion is that our technological religion blinds us from the truth.
I spent countless hours arguing about why Macs sucked so much before I had even really used one. Ironically, I am writing this post on a Mac right now, but I am using Windows Live Writer which I am accessing through remote desktop. Oh, and this blog post, well, it is actually hosted on an Ubuntu Linux server in the cloud on a PHP application you may have heard of called WordPress.
My point is, most of us vehemently will argue that our technology choice is the best without even having really tried the alternatives.
It seems ludicrous when you think about it clearly, but I still catch myself doing it even today.
When I look within myself to honestly ask the question "why," I find that most of my motivations come from a combination of pride in what I have learned and accomplished and a fear of what I don't know.
I find that it is much easier to dismiss a technology that I don't know as "garbage" or "worthless" than it is to take the time to learn about it and see why others like it so much. As they say, one man's garbage is another man's treasure.
The problem with thoughtless religion
I don't need to tell you that mindless religious zealotry is a destructive force in our world. You only need to go to your favorite national news web site or look in any history book to see that is the case.
But, while not too many programmers will draw swords over PHP vs C#—although I have been accused myself of throwing a chair in a similar dispute, a litigious and quite false accusation which I protest strongly to this day—many developers are quite willing to argue loudly about their opinions and even brashly tear down the works of others as I am sure you have seen if you have spent much time on the good ol' interwebs. I got a nice taste of this bitter water myself when I had the gall to actually post something negative about everyone's bastard child of a language that was discovered to have royal blood after some years of abuse, JavaScript.
So, while we may think our ignorance isn't harming anyone and that they deserve it anyway because they are clearly wrong, the truth is, there is quite a wake of destruction that our ignorance can leave behind us.
I look back on my own past and I am embarrassed that I harassed Perl developers to the degree that I did, completely discrediting their work and ignorantly pushing my holy statically typed C-based languages as their one and only savior who could cleanse them of their filth.
But more than anything, I realize that I hurt myself.
Stop hitting yourself, idiot!
The biggest growth in my career came when I was looking for a job doing C# development and found a really good opportunity to act as a technical architect for a project written in Java.
I was quite torn by the decision. In my heart I knew that Java was bad and evil. I knew that because Java lacked properties like C# and required the use of manually created getters and setters that everyone writing Java code was clearly an idiot.
I almost didn't take the job, but I decided that the pay was too good to pass up and that I would suffer through this awful experience like a prisoner of war until one day my Microsoft would rescue me. I thought I would at least get to apostatize some filthy Java writing scoundrels.
Well, it turned out that after a couple of years of mentoring developers on writing good Java code and unit testing, I realized that not only was Java not so bad, but there were some actual merits of the language and Java frameworks that could be appreciated.
More importantly though, I began to realize that my past code bigotry had closed quite a few doors on my face. It began to occur to me that perhaps all of my technology choices in the past were not necessarily the best. I began to start thinking that there wasn't actually all the much difference between many of the most popular technologies.
I began to realize that understanding a wide range of technologies and programming languages made me much more valuable than ignorantly subscribing to my own religion about a particular technology that I happened to choose.
I found that my own understanding of individual technologies increased rapidly, because instead of just "eating what I was fed," I could use my brain to compare and contrast differences between programming languages and technologies which left me with a deeper understanding of all of then.
I was rudely reminded of my own shortcomings that still exist in this area when I recently converted my blogs over to a Linux server in the cloud from Digital Ocean.
I was predisposed to choose Windows technologies for deploying web applications, but it was pretty hard to argue that a complete Linux server in the cloud that performed extremely well for $10 a month was not a good choice.
My point in all this is to say that being closed-minded about technology choices only hurts yourself in the end and severely limits your personal growth as a developer.
(Here are two good books to break down those barriers: Seven Languages in Seven Weeks and Seven Databases in Seven Weeks.)
There is no "best"
I'll finish up this post by imploring you to believe me when I say "there is no best technology or programming language."
I'm not going to insult your intelligence by saying that each language has a purpose for a different situation because the truth is much deeper than that.
After creating over 40 Pluralsight courses on a very wide range of technologies and programming languages, I've discovered a few truths.
The truth is that there are multiple great ways to do the same thing using different tools and different technologies.
The truth is that all programming languages and technologies have big mistakes and weaknesses in them.
The truth is the more you learn about different technologies, the more you will find that at the core most things are pretty similar. What I mean by this is that most of the core concepts about writing software apply regardless of technology choice or programming language syntax.
You'll also find, as I have, that if you are accepting about others technology choices and are able to admit your own ignorance and learn from it, you'll find helpful friendly people willing to teach you what they know, everywhere you go.
If you found this post useful–or at the very least entertaining–sign up here and join the thousands of other Simple Programmers out there. Also, I'm still preselling my complete package on How To Market Yourself as a Software Developer for a limited time.
(Side note: you may think that I am a big hypocrite with this post, since not too long ago I claimed that C++ was not back and JavaScript was doomed. I believe what I said in those posts does hold true and I don't think it is contrary to what I am saying in this post. It is possible to have actual critical opinions of technologies you have actually used. You don't have to like everything. My point is that, even though I dislike C++ for many of today's programming problems and I feel that JavaScript is not the most elegant language for the web, I do recognize that both of these languages have their merits and that they are valid choices in many situations.)
Getting Started With Google's Dart Language
I was a little skeptical of the Dart language when Google first announced it.
When I looked at the syntax of the language I thought that it didn't really seem to offer anything new.
Why create another language that is not very different than what we already have?
How is this actually much better than JavaScript?
But after having worked with Dart now for quite awhile and producing a Pluralsight course on Dart, I've completely changed my mind.
The Dart language is awesome!
What makes the Dart language so awesome is all the little subtleties the language designers added to the language, not any major new concepts or ideas.
When I started writing Dart code it felt exactly right. It felt like all the little annoyances that I had with languages like C#, Java and JavaScript were removed by the Dart language.
In fact, the real beauty of Dart is that if you already know C# or Java and JavaScript, you'll probably be able to learn enough about the Dart language to be productive in Dart in less than an hour.
Before I show you just how easy it is to get started, let me briefly tell you what the Dart language is:
- Object oriented. Everything is an object including primitives and nulls
- Optionally typed. You can add type annotations which static checking tools can use to help you find errors in your code, but you don't have to use them.
- Interpreted. Dart is run in a VM, but it is not compiled first. Round-trip time for making changes is very short.
- FAST! Dart is very fast, much faster than JavaScript in just about every test.
Some cool language features that I like about the Dart language:
- Mixins. Instead of using inheritance, you can use a mixin to add functionality to a class without directly inheriting from another class.
- Isolates. Instead of threads, the Dart language uses isolates for concurrency. Isolates can't actually share any memory, they pass information though messages. It is very hard to shoot yourself in the foot.
- Simplified built-in types. Numbers can be either int or double, and you can just use num, if you don't care. Lists and maps can be declared as literals. An array is just a special case of a list.
- Functions are first-class objects. You can pass them around just like any other object. There is even a lambda-like short-hand for creating a one-liner function.
- Top level functions and variables. Don't want to put a function or variable in a class? Good, you don't have to. In the Dart language, you can declare them anywhere you want.
- Simplified classes. There is short-hand for declaring constructors that assign parameters to class members. Class members don't have protected, private, public. Member variables are automatically properties.
- String interpolation. No more string format methods, just use the $variableName in a string to have its value expanded.
Getting setup with the Dart language
Ready to get running in 5 minutes?
Ok, read on.
Step 1: Go to http://dartlang.org and click "Get started."
Step 2: Download Dart (64-bit or 32-bit.) Unzip the file and copy the "dart" folder to where you want Dart installed.
This folder will contain the Dart Editor, the Dart SDK and the Chromium web browser which has a built-in Dart VM.
Step 3: Run DartEditor.exe
That is it, now you are ready to rock some Dart code!
Creating your first Dart language App
I'm going to walk you through a real simple example that will show you how to create a basic Dart application that is able to respond to a button click and manipulate some DOM data. For more advanced examples, you can check out my recently released Pluralsight course on Creating Web Applications with Dart. (I will plug this one more time before this post is over… wait for it…)
Step 1:
Go to File –> New Application.
Fill in your application name. I'll call mine HelloWorldDartWeb.
Leave "Generate sample content" checked.
Select "Web application."
Step 2:
Open the helloworlddartweb.html file and clear out everything in the body element except for the two script tags at the bottom.
The first script tag imports our actual Dart file, just like you would use to add JavaScript to a page.
The second script adds Dart support to the browser.
Step 3:
Add the following HTML to the body tag in the helloworlddartweb.html file:
<button id="theButton" >Press Me!</button> <div id="resultDiv"></div>
This will just create a button and a div. We are going to add some Dart code to respond to a button click and populate the div with some text.
Step 4:
Open the helloworlddartweb.dart file and clear out everything in main() and delete the reverseText function.
Notice that there are only two things we really will need in our .dart file. Just an import 'dart:html', to import that html library for Dart, and the main function, which executes as soon the DOM content is loaded on the page.
Step 5:
Edit the helloworldweb.dart file to make it look like this:
import 'dart:html'; void main() { var button = query("#theButton"); button.onClick.listen(addResult); } void addResult(Event e) { var resultDiv = query("#resultDiv"); resultDiv.text = "You clicked the button"; }
This code simply gets the button using a CSS selector. It uses the query function to do this.
Then we register the addResult function as an event handler for the onClick event for the button.
In the addResult function, we simply query for the resultDiv and change its text.
After you run this example, you should see a result like this:
Step 6:
Now change the Dart code to look like this:
import 'dart:html'; void main() { query("#theButton") .onClick.listen( (e) => query("#resultDiv").text = "You clicked the button!" ); }
Try running the code again and you should see it works exactly as before. Here we just shortened the code to a single line by using the short-hand function syntax.
Going further with the Dart language
So, that is just the basics of Dart. I wanted to show you how to get started really quickly, but I am sure there is more you will want to learn about Dart.
We can of course do much more with Dart, especially when building web applications. There is a Dart Web UI library which can be used to do templating and data binding so we can simplify our Dart code even further.
The language itself is pretty simple. Most C# and Java developers, as well as JavaScript developers, should be able to read and understand Dart code without any assistance. But here is a link to an overview of the language.
If you are looking for a more in-depth coverage of the Dart language and want to see how to build a real application with Dart, check out my Introduction To Building Web Applications With Dart course on Pluralsight, where I go over the entire language and guide you through building a real application, as well as cover some of the more advanced features like mixins and isolates.
Also, I could only find two books on the Dart Language.
I don't know if Dart will end up replacing JavaScript, but I do think Dart has the potential. It really is an awesome language that is fun to develop in.
That is strong praise coming from me, since I really tend to dislike dynamic languages. The creators of Dart have really done a good job of creating a language that is succinct, fast, easy to work with and has the best advantages of strongly typed languages with all the flexibility of dynamic languages like JavaScript.
Get Up and CODE and YouTube Videos
For those of you who frequent my blog and are looking for my latest Get Up and CODE podcast episode and YouTube video for the week, I have a bit of an announcement.
I am going to start posting these blog posts every Monday.
The YouTube videos will be going up every Wednesday.
The Get Up and CODE podcast will be coming on every Friday.
When my new website design is done, you'll be able to find the latest episodes of each on the side bar, so I'll stop including them in each weekly post.
But here is last week Get Up and CODE, where Iris and I talk about basic weight training.
Get Up And Code 006: Basic Weight Training
Podcast: Play in new window | Download
Getting Started With Glimpse In ASP.NET MVC
If you are using ASP.NET, especially if you are using ASP.NET MVC, you need to be using Glimpse.
I'm currently working on a more exhaustive Pluralsight course on Glimpse, (the course is now live!) but I thought I'd write up a quick getting started tutorial here.
What is Glimpse?
Perhaps you haven't heard of Glimpse yet, or you are just a little unsure of exactly what it is.
Glimpse is basically an open source and free diagnostics platform for the web. Right now it works best with ASP.NET and especially ASP.NET MVC, but it can be extended to other platforms as well. There is already work started for a PHP version and even a Python port.
What Glimpse essentially does is let you see diagnostics information about what is happening on your server directly in your page through a small diagnostics window completely rendered in JavaScript.
Out of the box, Glimpse can show you all kinds of information about your MVC application, like what routes are registered, what the flow was through the MVC pipeline and how the models were bound.
(BTW, if you are looking to brush up on your ASP.NET MVC 4 skills or learn about ASP.NET MVC 4, I recommend Professional ASP.NET MVC 4. Great book, top notch authors.)
Here is what the Glimpse window looks like on a page.
Glimpse is also fully extendable.
There are already plugins for Entity Framework, NHibernate, Ninject and many, many more
The best part about Glimpse is how easy it is to get setup.
I'll walk you through the steps below.
Step 1: Get Glimpse from NuGet
All you have to do to get Glimpse installed is simply either:
- Open up the Package Manager Console and type "Install-Package Glimpse.Mvc4" (or "Glimpse.AspNet" if you aren't using MVC)
- Or, right click on your references, select Manage NuGet Packages, then search for Glimpse and find the appropriate Glimpse package.
One you've done that, Glimpse will automatically add a few entries to your web.config for you.
Step 2: Turn on Glimpse
Turning on Glimpse is super easy.
Just launch your app and navigate to glimpse.axd. Then, click "Turn Glimpse On" to set a cookie that will tell the Glimpse component running on the server to send you Glimpse data.
Go to glimpse.axd
Turn it on!
It's that simple!
Step 3: Fire it up
Now all you have to do is navigate to any page in your application and you'll see this little icon at the bottom right hand corner of the screen:
If you click the icon, you'll see the Glimpse panel, which currently looks similar to the Chrome Dev Tools panel.
Using Glimpse
Each tab contains different diagnostics information about your application.
This data can be extremely helpful in troubleshooting problems and learning about exactly what is going on inside of MVC.
You can also find plugins that can be easily installed from NuGet.
For example, if you add the Entity Framework plugin, you'll start seeing a tab that shows data about EF queries, like this:
I'm pretty excited about Glimpse and its future. Anthony van der Hoorn and Nik Molnar, the two creators and main maintainers for Glimpse, have done an excellent job transforming how we get diagnostics information for web applications.
One of the things I find most exciting about this platform is how easy it is to extend.
In my upcoming Pluralsight course, (the course is now live!) I walk you through creating a Glimpse plugin, which is surprisingly easy.
So if you haven't checked out Glimpse, what are you waiting for? Go do it now, it will take you about 5 minutes to get setup.
What do you think? Are you using Glimpse already? Post a comment and let me know.
My YouTube video for the week: (This is not an ad!)
And here is the weekly Get Up and Code episode:
Why JavaScript Is Doomed
Update: I posted an update to this post where I talk about why I was wrong about JavaScript here. We are all human, we all make mistakes. I'm leaving this post and not deleting it, because I think it is important to learn from our mistakes.
JavaScript is a bubble.
Just like the housing bubble.
Just like the .COM bubble.
And just like any bubble, the JavaScript bubble is bound to pop.
Sure, JavaScript is everywhere. It appears to be growing at a rapid pace. But I'm willing to bet that we are getting close to a complete reversal that will throw JavaScript down from its throne, shattering its JQuery scepter with it.
JavaScript never really made a comeback
Part of the problem with JavaScript is that it's propped up on the back of another technology. See, JavaScript itself was rejected long ago. If JavaScript was a wonderful language to develop in, its wonders would have been praised years ago when it was first introduced. But I remember cursing JavaScript 15 years or so ago. And I wasn't alone.
Yes, I know it was a dark time, but recall, if you will, your pure hatred for JavaScript. You know, before it was so cool.
Then how did this ugly wart of a language become so popular?
Well, you see, it was this little library called JQuery. JQuery solved a very real and annoying set of problems that wasn't around when JavaScript was first invented: manipulating the DOM and making Ajax calls.
JQuery was basically designed to make JavaScript possible to work with. Before JQuery, DOM manipulation and Ajax calls were difficult. After JQuery, they were easy.
So JQuery ended up being this big band-aid that covered up all the ugly JavaScript code you didn't want to write and made doing what you wanted to do much easier.
You may disagree with me on this point, and you are welcome to do so, but even if JQuery isn't the reason JavaScript is so hot right now, do you honestly think JavaScript would have become so popular if JQuery never existed?
The problem with JavaScript
I want to love JavaScript. I really do.
I know it doesn't sound like I do, but just like I can't make myself like sweet potatoes—even though I know how good they are for me—I can't like JavaScript.
I've tried many things. I've put some butter and brown sugar on a freshly baked sweet potato. I've doused it with hot sauce. I've even pretended it was a regular potato and dressed it up like one. But, the fact remains, I just don't like sweet potatoes. It's something in their very nature that I despise.
I've tried the same thing with JavaScript. I've added libraries that make it much sweeter, like JQuery and Backbone.js. I've used tools like CoffeeScript and TypeScript to try and pretend it was a more palatable language. But the fact remains, JavaScript has some things that are fundamentally wrong with it that no amount of covering up or pretending will fix.
If JavaScript wasn't so ugly at heart, then a book called "JavaScript, The Good Parts," probably wouldn't be the #1 best-selling book on Amazon for JavaScript, the #3 best-selling book on web development, and the #4 best-selling book on software development, would it? (Go ahead and check it out for yourself if you don't believe me.)
I don't really need to tell you again what is wrong with JavaScript. If you use JavaScript, you know. If you don't use JavaScript, just search for "why JavaScript sucks" on Google and you'll get plenty of answers.
The point is, unless we are going to be completely disillusioned about it, we can probably all agree that JavaScript is not the greatest programming language that was ever created, and that it has some glaring weaknesses.
My point is not to bash JavaScript
Before you pitchfork me, I want to clear a few things up.
I don't hate JavaScript.
I don't suggest you shun JavaScript and go off with me to a floating island in international waters where we will build a new internet, one that isn't infected by JavaScript.
I actually use JavaScript.
Not only do I use JavaScript, but I have to use JavaScript and so do you.
And if you are smart and want to have a good career in software development, you'll take everything I am saying with a grain of salt, knowing that I could be completely wrong.
If you are smart, you won't just dump JavaScript out the window, betting that it will fail, because it might not. It might grow to become the one universal language that replaces all other programming languages. JSON sempiternus!
But, on the other hand, if you are smart, you won't put all your eggs in the JavaScript basket either. Even though the world seems bright and cheery for JavaScript developers today, it also seemed equally bright and cheery for Blackberry devs not too long ago. And look how that turned out.
And if you are solely a JavaScript developer or you really like JavaScript, I sincerely don't mean to offend you, but I offer this piece of advice: You are not the technology you happen to be using.
Trust me, if you're a good developer, you'll still be a good developer even if JavaScript goes away.
What is actually awesome about JavaScript has nothing to do with JavaScript
No one gets up in the morning and says, I want to have bamboo shoots shoved under my fingernails. (Ok, well maybe some people do, but those guys are still writing object-oriented Perl.)
Yet, at the same time so many developers get up in the morning, fire up their IDE—or excuse me, lightweight text editor which has 50 plugins installed to give the capabilities of an IDE, but is not an IDE—and write JavaScript code. Why do they do it, unless they think JavaScript really is awesome?
It's because all the stuff around JavaScript and built with JavaScript and on top of JavaScript is actually pretty awesome.
As much as I loathe JavaScript itself, frameworks like JQuery, Durandel, Backbone, Angular, Knockout and more are pretty darn cool.
Not only that, but JavaScript is everywhere!
There are even cool server technologies, like Node.js that are built with JavaScript.
This is the part where I tell you what is not to love
What's not to love, is that all of that stuff has nothing to do with JavaScript itself.
Take JavaScript away and replace it with another programming language and you don't really miss anything.
Ever seen a movie star without her makeup? Makes you realize that any halfway decent looking woman could be a movie star, with the proper styling.
The same goes for JavaScript. It is a language that has been dressed up to look like something it is not. What we all love about JavaScript is not the language itself, but all that makeup that has been caked on, a little bit of mysterious seduction it infers, and the stylish clothes it wears.
But, what is starting to happen already, and what I believe will continue to happen, is that people will start to get sick of that caked-on makeup look and high maintenance personality of JavaScript.
All those frameworks were really useful at first, but they are becoming such a huge mental burden. Are you worried about what JavaScript framework you need to master and keeping up with what is the hot one to use on any given day? I am.
You can only build so much on top of something else, before you have to wipe the slate clean and start over.
I don't know when this will happen with JavaScript, but I am pretty sure it will happen.
It is very likely that a language like Dart, that can do everything JavaScript can do and more, will likely someday dethrone our web development king.
JSON sempiternus!
By the way, check out my new experiment on YouTube, going to release a short video each week. Let me know what you think.
OAuth and REST in Android: Part 2
In my last post we went over OAuth in general and we looked at how to use a Java library called Leeloo to authenticate with a service providing an OAuth 2 implementation.
Now that we are able to authenticate a service with OAuth, we need to be able to actually use that service to do something useful.
Many popular web service APIs like Facebook and Twitter provide a REST based implementation.
In this post I'll show you how to easily connect to one of these web services from Android and parse any responses you get back.
Should I use a REST library?
This is a valid question we should address before getting into the details.
My answer to this question is basically "no."
I first tried the approach of using a REST library to make it easier to communicate to a REST based web service, but quickly found the overhead of the library was more than the benefit it provided.
If you come from a background of calling XML and SOAP based web services, you might be surprised by this answer. With SOAP based web services it was a huge benefit to use a library to generate a proxy for you to call the web service and let you not have to worry about parsing XML and SOAP headers.
With REST it is completely different. The whole point of moving to REST based web services is to simplify the process of calling web services.
Most REST based web service interfaces are extremely simple to use. The idea is that the URL itself contains as much of the data as possible and additional data is included in the POST body.
By adding the complexity of learning a REST library and implementing the proper interfaces required to make it work seamlessly, we can easily add more complexity and overhead than just creating a HTTP request ourselves and parsing the responses.
For this approach I am going to show you how to do just that.
Calling the REST service
In order to call a REST service in Android we are going to first have to discover and understand the REST API provided to us, then make the appropriate calls with the OAuth token we got from authenticating. Finally, we will parse the result of the call and get back our response.
Discovering the API
Because REST is not really a standard, but rather an ideal, there is not a standard way REST APIs are implemented.
You'll have to take a look at the documentation for the REST API you want to call to figure out exactly what a call should look like.
In general though a REST API will involve making some kind of HTTP GET, POST, PUT or DELETE request and passing data through the URL or in the request body.
Here is an example of the Dailymile.com API which I have been recently integrating my app to use.
You can see the full API documentation here.
For this API, I am going to show you how I am creating a workout entry using a post.
Making the REST call
In order to make a REST call in Android, we are going to use a HttpClient object and the appropriate http request class.
In this example we are going to use the JSONObject class to create some data in JSON format that we can pass to the REST call by embedding it in the post.
I looked at the API for posting a workout entry to Dailymile, and the format of the request should look like this:
The API also indicates that it expects the post body to contain some JSON and gives us a list of required and optional entries that need to be in that JSON object.
Let's take a look at how I am making this call and then we'll break it down some.
HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost( "https://api.dailymile.com/entries.json?oauth_token=" + token); httpPost.setHeader("content-type", "application/json"); JSONObject data = new JSONObject(); data.put("message", dailyMilePost.getMessage()); JSONObject workoutData = new JSONObject(); data.put("workout", workoutData); workoutData.put("activity_type", dailyMilePost.getActivityType()); workoutData.put("completed_at", dailyMilePost.getCompletedAt()); JSONObject distanceData = new JSONObject(); workoutData.put("distance", distanceData); distanceData.put("value", dailyMilePost.getDistanceValue()); distanceData.put("units", dailyMilePost.getDistanceUnits()); workoutData.put("duration", dailyMilePost.getDurationInSeconds()); workoutData.put("title", dailyMilePost.getTitle()); workoutData.put("felt", dailyMilePost.getFelt()); StringEntity entity = new StringEntity(data.toString()); httpPost.setEntity(entity); HttpResponse response = httpClient.execute(httpPost);
You can see that I am first creating an HttpClient object and an HttpPost object. The HttpPost has its URL set to the URL for the API call and I am adding a query string parameter to provide the OAuth token we got when when authenticated in my previous post.
I set the content type to be JSON so that we can get back a JSON object from the API call and so it knows that we are passing JSON data.
Then I construct a JSON object in the format specified by the API. The way to construct the JSON object is to basically create a set of keys and values that are specified by the API you are calling. In this instance I have a "message" key which I put the message data into.
The only tricky part is that JSON objects can be nested. So if you look at the key "workout" in the example above, I am creating a brand new JSON object to use as the value for that key which has its own subkeys which could contain more JSON objects.
Doing it this way is much more simple than trying to construct the string yourself. The string we end up constructing will look something like this:
Finally, I put the JSON data into a StringEntity class and set it as the entity on the HTTP Post. Then we can call execute on the HttpClient to execute the HTTP POST.
Handling the response
HttpResponse response = httpClient.execute(httpPost); String responseString = EntityUtils.toString(response.getEntity()); JSONObject responseJSON = new JSONObject(responseString); int workoutId = responseJSON.getInt("id");
All we are doing in this case is getting the response from the execute call on the HttpClient object, then using EntityUtils.toString to convert the response's entity to a string representation. Finally, we construct a new JSONObject from that string.
We can then easily extract any data out of the JSON object by using the methods on that JSON object that let us get typed values out of it. For this example, I know that I am getting back some JSON that has a key "id" which is the id of the workout I created with my POST.
It is really that simple
The example I am showing you here is one of the more complex examples of calling a REST based API, because we are having to POST and parse JSON data.
In many API calls, you can just use an HTTP GET or a POST without any data to accomplish what you need to in the API.
Some REST based APIs will allow or require data to be passed in a different format, but most of them use JSON notation, which I find the easiest to work with.
Hopefully with these series of posts you can now authenticate against an OAuth 2 based service and make calls to the API to get and manipulate data in Android.
If you have any questions, feel free to drop me a line or post in the comments below.
As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple. Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week. Also, you can follow me on twitter here.
OAuth and REST in Android: Part 1
I recently had the fun experience of learning a bit about both OAuth and making REST web service calls in Android and since I didn't find much good material out there, I thought I would share it here.
Let's talk about OAuth
The first thing you NEED to know about OAuth is that OAuth and OAuth 2.0 are not the same protocol.
From the OAuth guide on hueniverse:
OAuth 2.0 is a completely new protocol and is not backwards compatible with previous versions. However, it retains the overall architecture and approach established by the previous versions, and the same introduction (from the Official Guide to OAuth 1.0) still very much applies.
But, before we get into that, let's talk a little bit about what OAuth is for.
OAuth basically does two things for a web site providing some kind of service or API that another application might want to use.
- It prevents the consuming application from needing to store or have the user's login and password.
- It allows for a scoping of access to the producer's services. (For example, a user might be able to login to a site and access all of the features, but an app using OAuth might only be granted permissions to do certain things.)
So now that we know why, let's talk about how both OAuth and OAuth 2 work from a high level perspective.
From the app developer perspective, the flow goes something like this:
- You register your application with the service you want to access and get some unique identifiers for your application.
- When you want to access something on the service, you make a request to the service using your unique identifier and telling it where to send the user after they authenticate. (Usually you would launch a browser window here.)
- User will login to the service using the browser window you launched for that service and choose to grant your application certain privileges.
- The service will redirect the user to the callback url you provided and include a code you can use to get an access token.
- You call the service one more time passing in your unique identifier and the code you got back and the service grants you an access token which you can use to access services you have been granted permissions for.
- The next time you need to make a call you can just use that access token instead of going through this whole process again. (At least till it expires.)
It really isn't that complicated; the basic idea is that you tell the service who you are and ask the user to authenticate themselves and grant permissions to your application. Then you prove that you got the response from the server and that it is still you and the service gives you a special pass to access the service.
The real difference between OAuth and OAuth 2 is the protocol itself, not the process. So this is both good and bad.
Good, because we don't have to change our process flow and understand something different.
Bad, because we can't use the same libraries to access an OAuth 2 implementation as we do for an OAuth implementation and vice versa. There is no backwards compatibility.
For the purpose of this post I am going to show how to use the Leeloo library to connect to an OAuth 2 service.
Connecting to OAuth 2.0
Download the library
The first thing you will want to do is to get the latest version of the Leeloo library. It has moved to the Apache Amber project, so this link might change, but for now I found the ready to download binaries here.
Configure build path
Once you have the library downloaded you'll want to add the following jars to your build path:
- jettison-1.2.jar
- oauth2-client.jar
- oauth2-common-0.1.jar
- slf4j-api.1.6.1.jar
Make initial request for authorization
Make sure you already have a unique client id created with the service you are going to access. Most services out there like Twitter have a page where you can request one for your application.
Once you have this, you will use this to create a url that you will redirect the user of your application to.
In the code snippet below, I am creating the url and then creating a new Intent in Android that will open a web browser at that url.
OAuthClientRequest request = null; request = OAuthClientRequest .authorizationLocation(authenticationUrl) .setClientId("<your client id>").setRedirectURI("<your redirect url>") .buildQueryMessage(); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(request.getLocationUri() + "&response_type=code")); startActivity(intent);
A couple of things to note about this code snippet:
- You'll need to replace client id with your client id and redirect URI with your redirect URI.
- The redirect URI for an Android application is going to be some protocol that doesn't really exist, but you can tell your application to respond to. (We'll cover that in the next step, but you might have some URI like myapp://oauthresponse)
- I had to add a "&response_type=code" to the end of my URL because the authentication service required it. You might have to look and see how the service you are trying to access expects requests to be formed.
Configure your application to respond to your unique URI
In the previous step we had set the redirect to a unique URI like "myapp://oauthresponse", now you will need to configure the activity you want to handle the response from the service to intercept that protocol.
You can do this by adding an intent filter to that activity like so:
<intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="myapp" android:host="oauthresponse"/> </intent-filter>
With this intent filter we are telling our activity to respond to a URI request in the form of "myapp://oauthresponse".
Configure your activity to respond to handle the intent you registered to receive
Next we'll want to set up an override in our activity to handle the new intent that will be called on our activity. We can then pull the code the service gave us out and use that to request a real token.
@Override protected void onNewIntent(Intent intent) { Uri uri = intent.getData(); if (uri != null && uri.toString() .startsWith("myapp://oauthresponse")) { String code = uri.getQueryParameter("code"); // ... } }
This code will allow us to respond to the intent that will be fired by the web browser when the service redirects the user to "myapp://oauthresponse."
Exchange the code for a token
Next we need to get a real token instead of a code. When the user typed in their username and password and granted access to our application, the server called our callback URI with a code that we extracted in the last step.
Now we can pass that code back up to the server along with our client secret and client id and get an access token.
OAuthClientRequest request = null; request = OAuthClientRequest.tokenLocation("<service request URL>") .setGrantType(GrantType.AUTHORIZATION_CODE) .setClientId("<your client id>") .setClientSecret("<your client secret>") .setRedirectURI("myapp://oauthresponse") .setCode(code) .buildBodyMessage(); OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); OAuthJSONAccessTokenResponse response = oAuthClient.accessToken(request); String token = response.getAccessToken();
In this bit of code we are sending back to the server all the information we have that identifies our application as well as the code that proves the user allowed us to access that service.
Then we get back an access token from the server. I would recommend you save this access token so that you don't have to do this reauthentication in the future.
Wrapping it up
So what we have been able to do here is to redirect a user to the right page to authenticate our application, and then wire up our activity to respond to the redirect the service gives us in order to ultimately get an access token we can use to prove we are authorized to access that service on behalf of the user.
Be cautious though, because not everyone is implementing OAuth 2.0 exactly the same way, since the spec is not finalized. So you might run into issues where things aren't working exactly as laid out in this post. If that is the case, you may have to modify a URL that is generated or something along those lines.
In my next post, I'll show you what you can actually do with your authorization token. We'll go through calling a REST based API web service from Android.
Feel free to post any questions in comments. I used this code to connect to the Dailymile.com API in my PaceMaker application.
As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple. Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week. Also, you can follow me on twitter here.
Getting up to BAT: Building a True DSL
If you've made it this far with your BAT implementation, you have finally arrived.
Not to say that you'll ever be done expanding your automation framework and building and improving your BATs, but you are at the point of having a mature usable BAT framework and you can be proud of that accomplishment.
If you truly want to see where the rabbit hole goes though… Read on
Taking it to 11
If you have designed a good automation framework for writing your BATs, you will most likely have created an internal domain specific language (DSL).
What is an internal DSL?
Basically it is a set of APIs and rules built in another language that function as their own language.
You might have some code that looks like this:
Pages.Login.Goto(); Pages.Login.LoginWithDefaultUser(); Pages.Customers.Goto(); Pages.Customers.AddNewCustomer();
You can see how this code is really looking like a language itself. It is hard to tell if this code is even C# or Java.
This is a good example of an internal DSL.
If we were to take this same section of a BAT test and write it as an external DSL, it might look something like this:
With a true DSL we can simplify even further to get right down to the bare minimum set of commands we need to execute what we want in our application.
How to implement a DSL?
There are a number of tools and techniques that can be used to create a DSL. I'll hit on some of those a bit later on, but first we need to design the DSL itself.
Designing a DSL can be challenging, but I have found the best approach is to use a similar approach to what we used to design our automation framework.
It is best to work backwards from the syntax that would make your BAT the easiest to write and the most clear. Once you have done that you can worry later about implementing the DSL to support the syntax you have come up with.
You should focus on creating a limited vocabulary for your DSL so that it will be easy for someone to learn and know what their options are.
The more restrictions we put into a DSL the easier that DSL becomes for doing a specific purpose.
We want to give the user of a DSL no more options than required for what they want to do and no less.
This isn't always easy to do. It often requires some careful thought and refinement.
Your DSL should also use terminology and phrases that are familiar to the business domain of your application. By doing this you will make it so someone understanding your application will understand BATs written in that DSL.
I also always try to make a BAT DSL read as much as plain English as possible.
Once you have designed the DSL, you will need a way to implement it.
I've written about using ANTLR to create an external DSL. Also I have written a review on a book that I recommend for learning ANTLR.
Microsoft also has a DSL SDK you can use in VS2010, although I haven't used it myself.
The basic idea behind implementing a DSL is that you have to take some sort of grammar you design for your DSL, parse it into a syntax tree, then use that tree to generate code that will actually perform the actions.
It is by no means a trivial task, but using a tool like ANTLR, makes it much simpler than trying to completely generate a parser and execution engine yourself.
Why even bother?
Creating a DSL for your BATs is completely optional, but there are some significant benefits to doing so.
The biggest one I have found is that you are much more likely to get business people to write BATs if you have a simple DSL they can use to create them. Once you get everyone using BATs to define behavior and requirements, communication becomes much more simple.
Another great thing about creating a DSL is that you can create a runner that can interpret the DSL BAT scripts which can be run on any machine. Typically, to run BATs created in Java or C#, you would need a C# or Java compiler and a test runner, etc. By creating a DSL and a stand alone executor, you can very easily allow anyone to run BATs with little to no setup.
Writing your BATs in a DSL will also make writing the BATs and understanding them much easier. A good DSL can get rid of all the little language and API nuances that don't really add information to the specific domain you are working in. A good DSL strips information down to the minimum amount needed and is able to do so, because it assumes the context is your application's business domain.
You will also find that you are better able to separate framework from tests when you have a DSL in place. One issue that many teams face when creating a BAT framework is that some people come along and write lower level code in the higher level BATs. This creates a problem because it is hard to force someone to use the higher level API when the framework and the BAT code are the same language.
Wrapping it up
So that completes my series on Getting up to BAT.
Hopefully you have learned enough to be able to implement your own BAT framework and get BATs running for your application.
I tried to cover most of the important steps here without getting too deep into the details.
If you have any questions or are interested in getting more in depth training or consulting on getting BATs setup for your environment, send me an email or leave a comment.
It can be a little difficult to get started and get a BAT framework up and running, but the rewards are well worth the effort!
As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple. Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week. Also, you can follow me on twitter here.
Getting up to BAT: Creating Your First Smoke Tests
If you have been following my posts so far on Becoming Bat Man, you should already have hired an automation lead, figured out what browser driver you are going to use and come up with a design plan for your automation framework.
Now you are probably faced with the difficult decision of…
Where to begin with your tests
I don't suggest writing your automation framework first and then writing tests to use it. If you go this route you'll have two problems
- It will be a long time and large investment before you see any fruits from your automation effort.
- Your framework will likely be designed incorrectly or not test-writer friendly. (Which is basically the same as wrong.)
What you really want to do is to write some basic tests that let the development of those tests drive the development of your framework.
The best tests to drive your framework are some basic "smoke tests." If you are not familiar with the term "smoke test," it basically means some tests that make sure the application you are testing is at least somewhat working and not completely broken.
There are a few different opinions of what exactly constitutes a smoke test, but in general, if you have any tests that you regularly run on a new build to make sure it is at least OK, those would be the tests we are interested in here.
You are going to want to start by taking the easiest and most simple tests you have and writing them in a concise syntax that you use to drive the development of your framework.
It is very important at this stage to not worry about what you think might be possible or how it would be implemented in the framework, but to instead focus and making the tests as terse and explanative as possible.
The basic idea is that you will write the test out in the syntax you would like to be able to use, then implement the framework features required to make that test pass. This whole process is very similar to doing Test Driven Development.
An example case
The easiest way to demonstrate this is with an example.
Let's say you have a smoke test like the following:
Create a new account, pick an on-sale item, add it to your cart and check out using PayPal. Verify that we hit the order success page.
We might write a test for this that looks something like:
Workflow.Users.CreateNewUser(); Pages.Login.LoginWithLastCreatedUser(); Pages.SaleItems.AddAnyToCart(); Workflow.Cart.CheckoutUsingPayPal(); Assert.True(Pages.Checkout.SuccessPage.IsAt());
What I just wrote above is astonishingly simple. You are likely saying to yourself something along the lines of "What if… blah."
Forget it! We'll handle "what if" later. Right now we are going to write the tests as terse as possible and not handle any other conditions.
What I wrote above is the style that I like to write the tests in, which is highly subject to opinion, but the content of what I wrote is not as subjective.
There are a few important points to note:
- I used methods like CreateNewUser, LoginWithLasteCreatedUser and CheckoutUsingPayPal that do a huge amount of work and have no parameters. Why? Because for the purpose of this test, (and you'll find for most of your tests), we don't care about what the first name or last name or address of the user is, we don't care how we get them logged in, and we only care that they checkout using PayPal, not what account is used, etc.
- I didn't declare any variables. Tests should be simple. Let the framework remember the state.
- I over-simplified. This is fine, you are working inside of a very specific domain. Let your test framework methods do one large thing. Don't worry about oversimplifying for now.
- I asserted something at the end. All tests need to assert something. If you can't figure out what to assert, work on redesigning the test before automating it.
- I didn't pass parameters. Avoid this also. This goes along with the first point, but is so important that I feel it is OK to state it twice. If you don't care about variation, eliminate it. You will constantly need to find places where a manual tester would have to enter specific information, but an automated test won't care what that information is.
- All my methods are static. While this would be bad in normal production code, for a test API it is the easiest for test writers to use. No variable declarations, no "newing" up objects, no constructors, etc.
- It's written in "business language." As close to the language an end user or business person would use to describe the test.
So, this test is definitely doing a huge amount of stuff in a few lines of code, and because of this your inclination would be to say that the API level is too high. Don't!
Instead, make the API level as high as you possibly can, until further tests you try to implement prove to you that it must be broken down further.
By working this way, you ensure a reduction in the total lines code and complexity of your tests by as much as possible.
You would NEVER work like this with normal code, but for automated tests this is essential. The main reason is because you will be calling the same methods perhaps 1000s of times, where in normal code you usually only reuse a method in a few places.
Next steps
For my example above, the next step would be going through and implementing all the framework methods required in order to make that test runnable. You will end up utilizing the general design you came up with for your automation framework to do this.
Then you will simply move on to the next test and repeat. Each time you should have less and less effort required, as more of the basic functionality of your automation framework is implemented.
Automating your smoke tests should ensure that you get a fairly even distribution of the framework code written as the smoke tests should cover many different areas of your software.
But, don't start adding these smoke tests to your build yet. We'll cover that in the next step. Adding them to the build prematurely can cause the confidence in these tests to be forever diminished! We don't want to do that!


text:
You've read all of your free items this month.
To register, get added benefits and unlimited access to articles, Become a Member. Already a Member? Sign in.
Hillary vs. Barack: Who Had the Smartest Media Strategy?
Optimedia's Antony Young Rates the Campaigns
Want more Access, Content & Connections? Upgrade to Membership.
We are glad you are enjoying Advertising Age. To get uninterrupted access and additional benefits, become a member today.
Already a member? Log in.

subset: commoncrawl


text:
- 21st Century Health
- California Gold Nutrition
- Carlson Labs
- Country Life
- Doctor's Best
- Enzymatic Therapy
- Enzymedica
- Garden of Life
- Healthy Origins
- iHerb Brands
- Jarrow Formulas
- Life Extension
- Madre Labs
- California Extracts
- Doctor's Best
- Eclectic Institute
- Gaia Herbs
- Jarrow Formulas
- Life Extension
- Natural Factors
- Acure Organics
- Alba Botanica
- AnneMarie Borlind
- Aubrey Organics
- Avalon Organics
- Aveeno
- Derma E
- Desert Essence
- Acure Organics
- Alba Botanica
- Andalou Naturals
- AnneMarie Borlind
- Aubrey Organics
- Avalon Organics
- Bee Naturals
Eidon Mineral Supplements, 镁浓缩液, 2 oz (60 ml)
- Ionic Mineral
- Mineral Dietary Supplement
- Suited for Vegan Diets
- Easy to Swallow
- Gentle on the Stomach
- Purity You Can See, Taste and Feel
Magnesium is an essential mineral involved in over 300 enzyme actions in the body.
Eidon Magnesium: Is essential for normal heart function, nerve impulse transmission, muscle relaxation and calcium management. Symptoms of deficiency may include muscle cramps, headache, fatigue, insomnia and involuntary twitches. Magnesium is depleted during stress - both physical and emotional.
30 drops per day, (2 ml) in 8 oz of juice or water.
De-ionized water.
No sugars, starch, artificial colors or flavors. No added preservatives. No animal by-products. Gluten free.
Store at room temperature, tightly closed.
Keep out of reach of children.
|Supplement Facts
|Amount per serving
|Magnesium (as magnesium chloride)
|80 mg
|** Daily Values (DV) not established.


text:
AFCAsianCUP – November 29, 1997 remains a painful scar on the collective consciousness of Australian football. After five consecutive failed attempts to qualify for the FIFA World Cup, the Socceroos had a terrific squad of players assembled to make a run for France '98. All that stood in their way...
- 1
- 2
- 3
- 4
- 5
Persepolis escape Cup embarassment, Esteghlal bow out [VIDEO]
Persianfootball.com – SIRJAN, Persepolis Tehran were fortunate to come back from a goal down against second league team Gol Gohar and eventually win on penalty kicks in Iran's Hazfi Cup quarterfinals on Thursday. The underdogs were even reduced to ten men early in the match, but held Persepolis to a...
Iran moves down five places in FIFA rankings
Tasnim – ZURICH, Iran has dropped five to 56th place in the latest FIFA rankings despite a win over South Korea in a friendly last week. Japan is the new number one side in Asia even though it dropped one spot to 53. South Korea and Uzbekistan are third and...
I wanted to rejoin Persepolis, Eamon Zayed says
Tehran Times – TEHRAN, Eamon Zayed has revealed he wanted to return to Persepolis before agreeing a move to Malaysian football team Sabah FA. Dublin-born Zayed, who spent the second half of last season on loan to Sligo Rovers, has joined Malaysian club Sabah Rhinos. "I know the coach (George...
Parviz Mazloumi Shortlisted for Paykan Job
Tasnim – TEHRAN, Former Esteghlal coach Parviz Mazloumi has been nominated to replace Mansour Ebrahimzadeh in Paykan football team. Mazloumi has been out of work for less than one year. Ebrahimzadeh stepped down as his job on Monday. According to the reports, Paykan has also negotiated with former Sepahan coach...
Persepolis Midfielder Haghighi Sidelined for One Month
Tasnim – TEHRAN, Persepolis of Tehran midfielder Reza Haghighi could be out for one month with a knee injury. Haghighi suffered a serious right foot injury in Sunday's game against Esteghlal in Tehran derby. "An MRI scan revealed a tear to his right knee. Haghighi has been sidelined for one...
Popular Articles (Weekly)
- Persepolis Defeats Esteghlal in Tehran Derby [VIDEO+PHOTOS]
- AFC Asian Cup player in focus : Iran's Sardar Azmoun
- Classic Rivalry | Australia vs Iran
- AFC 60th Anniversary: Ali Karimi, A True Asian Icon
- Ali Daei among AFC Inductees in Hall of Fame
- Iran moves down five places in FIFA rankings
- Coaches' reactions to Tehran derby
- Iran Beach Soccer Team Wins Gold At The Asian Beach Games 2014


text:
Hi Cream,
490 defense is the magic number to make you crit immune vs. all mobs in the game, including bosses. Going above 490 is not a bad thing, defense is the second best avoidance stat after pure dodge rating (as is increases your dodge, parry, and chance to be missed all at once). As for socketing, you would want to put +12 stam gems in exclusively (a few exceptions) to maximize your health pool after you reach the 490 def mark.


text:
Getting Started How-Tos
Aspect Framework
Injecting Behaviors before and after Method Execution
Intercepting Properties and Fields
Injecting Behaviors into Iterators
Architecture Framework
Restricting interface implementation
Diagnostics Pattern Library
Model Pattern Library
Automatically Implementing INotifyPropertyChanged
Dispatching a Method Execution to the GUI Thread
Backing a Property with a Registry Value
Dynamically Introducing an Interface
Adding DataContract and DataMember Attributes
Blog Series
15 Days of PostSharp Principles
Day 2 - Applying Aspects with Multicasting Part 1
Day 3 - Applying Aspects with Multicasting Part 2
Day 4 - OnMethodBoundaryAspect
Day 6 - Your code after PostSharp
Day 7 Interception Aspects – Part 1
Day 9 - Aspect Lifetime & Scope Part 1
Day 10 - Day 10 Aspect Lifetime & Scope Part 2
Day 11 - EventInterceptionAspect
Day 12 – Aspect Providers, Part 1
Day 13 – Aspect Providers, Part 2
Day 14 – Introducing Members and Interfaces, Part 1
5 Ways to SOLIDify Your Code
AOP in .NET by Matthew D. Groves
The book AOP in .NET introduces aspect-oriented programming to .NET developers and provides practical guidance on how to get the most benefit from this technique in your everyday coding. The book's many examples concentrate on modularizing non-functional requirements that often sprawl throughout object-oriented projects.
About the author: Matthew Groves is a Microsoft MVP with over ten years of professional experience working with C#, ASP.NET, JavaScript, and PHP.download free chapter


text:
view bio »
In a unanimous vote this morning, Hamilton County commissioners agreed to transfer $10 million of Erlanger money that the hospital will use to draw as much as $30 million in federal funds to offset care for the uninsured.
The maneuver, known as an intergovernmental transfer, allows the county to transfer $10 million of Erlanger money through the state and federal government. That money will be used to draw millions more from what's called the Public Hospital Supplemental Payment Pool.
Erlanger executives learned in early April that the hospital, which has struggled financially in recent years, that the hospital would have access to the supplemental payment pool.
Erlanger had been left out of the pool while both Nashville General Hospital and the Regional Medical Center in Memphis have received millions from it. The Centers for Medicaid and Medicare Services approved a waiver to include Erlanger.
Read more in tomorrow's Times Free Press.
More recent Erlanger news:
Louie Brogdon began reporting with the Chattanooga Times Free Press in February 2013. Before he came to the Scenic City, Louie lived on St. Simons Island, Ga. and covered crime, courts, environment and government at the Brunswick News, a 17,000-circulation daily on the Georgia coast. While there, he was awarded for investigative reporting on police discipline and other law enforcement issues by the Georgia Press Association. For the Times Free Press, Louie covers Hamilton County ...


text:
andrew cuomo
Results: 1 - 4 of 4
Death Race
Is It 2016 Yet? GQ Checks Out the Democrats Already In the Running
Last week in Charlotte, the 2012 presidential campaign was front and center and in high-definition on the stage of the Time-Warner Cable Arena. But on the outskirts of the city, under a white party... read more
Wednesday, 9/12/2012 at 2:13PM
Death Race
Why "Martin O'Malley" and "2016" Always Appear in The Same Sentence
For the last hour, students stood or sat on the floor playing on their cellphones under blue and red balloon clusters in the gym at Bowie State University, just outside of Washington. Maryland's Governor,... read more
Wednesday, 5/9/2012 at 8:00AM
News + Politics
The (Real) Governator
Nope, not Ah-nold. On January 1, 2011, Andrew Cuomo rolled into the perpetually dysfunctional city of Albany, New York, and did something truly shocking: He delivered on his campaign promises. Here, in his first major interview since taking office, the nation's most popular governor tells Lisa DePaulo what it's like to grow up as the Son of Mario, how he pushed gay marriage into law, and whether we can start printing those CUOMO FOR PRESIDENT bumper stickers read more
January 2012
- Tags:
- News + Politics,
- Andrew Cuomo,
- President
The Magazine
Letter from the Editor, November 2010
Mad About You read more
November 2010
Results: 1 - 4 of 4
- What to Wear Today: 11.27.14
- Instajack: Momofuku Founder David Chang
- Your Daily Eye Queue: Adidas Designer Nic Galway on The Tubular Runner, Miley Cyrus' Furry Pink Jacket, and More
- Why You Should Never Wear $600 Sneakers to Thanksgiving Dinner
- What to Wear Today: 11.26.14
- Over 100 Black Friday Deals You Can Start Shopping Right Now
News + Politics
How To
Food + Travel
- David Chang's Kitchen: Don't Get All "Fresh" with Me
- David Chang's Kitchen: Your Idea of Bologna is Total Baloney
- Chart: The Family Tree of Bourbon Whiskey
- Recipe: Semi-Summer Salad - Chef Jeff Taibe of Oak + Almond
- The Great Franco-Italian Pasta Experiment
- How to Pick from an Overpriced Restaurant Wine List


text:
Soil and water conservation, wildlife program sign-up extended
The U.S. Department of Agriculture Natural Resources Conservation Service is extending the cut-off date for conservation applications until Feb. 13 for two of its main programs, according to Steve Chick, NRCS State Conservationist.
Most NRCS programs are already in a continual sign-up process, but on Feb. 13, we will rank the applications we have and begin to prepare contracts with producers, said Chick. Contracts will be completed after the ranking; however this process may not be done in time before spring 2009 planting. Last October we had a cutoff thinking we would have the program rules from Washington shortly thereafter. We are still waiting for the rules so we wanted to give producers an added opportunity to apply. We will continue to take applications after that date and will fund those applications as money is available, he said.
The two programs with the extended deadline are the Environmental Quality Incentives Program and the Wildlife Habitat Incentives Program.
Last year in EQIP more than $29 million federal dollars in nearly 1,500 contracts were written in Nebraska. Terraces, fences, livestock watering tanks and pipelines to improve grazing, and low pressure irrigation systems to use less water are just some of the conservation practices applied. Assistance for animal manure systems is another growing request. "Landowners also contributed funds which show a high level of interest in protecting our natural resources," said Chick.
In the WHIP area for 2008, over $1.2 million was committed to wildlife habitat development practices.
There are several special initiatives in the EQIP funding. Some of those are: invasive species control in 11 natural resources districts, water quantity actions along Elm and Lodgepole Creeks, animal feeding operations statewide, NE Natural Legacy Project sites, and water quality efforts in state identified locations. Producers should ask their local NRCS office for details if they are interested in these initiatives.
"There are other incentives like added cost share funds or 'up front money' for beginning farmers or ranchers (those generally in their first 10 years) and socially disadvantaged (ethnic) farmers or ranchers. People in these categories need to self-identify themselves during the application process," said Chick. In 2008, 76 beginning farmers received nearly $2.8 million in cost-share funds.
All these applications can become a long term contract up to 10 years; however people need to know they will have to begin some of the conservation work in the first year. The contract is written and cost-share dollars are set at the time of contract signing. Inflation can work against you if you wait to long to install the practices, added Chick.
Producers wishing to update an existing application or make a new application are encouraged to contact the Natural Resources Conservation Service office in the USDA Service Center soon.
Date: 1/13/09


text:
view bio »
Colts quarterback Peyton Manning has a long walk back to the locker room by himself after a field goal by the Houston Texans beat the Colts on Dec. 24, 2006. Manning is considering joining the Tennessee Titans and worked out with them Sunday in Knoxville. Photo by Matt Detrich/Indianapolis Star
DENVER — The big deal is done. Peyton Manning is a Denver Bronco.
A person familiar with negotiations says that Manning and the Broncos completed his five-year contract worth about $96 million this morning.
The person spoke on condition of anonymity because Manning is to be introduced at a news conference at Broncos headquarters later.
The agreement ends a wild chase for perhaps the most valued free agent in the history of the NFL, a quarterback who has won an unprecedented four league MVP awards and took the Indianapolis Colts to a Super Bowl victory in 2007.
It also represents a huge coup for Broncos executive and Hall of Fame QB John Elway, and could spell the end of the Denver career of Tim Tebow, last year's quarterbacking sensation.
Turns out Tebowmania may have just been a fad in the Mile High City.
ESPN and the NFL Network first reported on the completion of the Manning deal.
Manning called Elway on Monday and told him that he had chosen Denver over the Tennessee Titans and San Francisco 49ers, his other final picks. The Broncos and Manning's agent then hashed out the contract details.
"I congratulate Peyton as he heads to a tremendous organization in the Denver Broncos. We wish him nothing but the best as he continues his Hall of Fame career," Colts owner Jim Irsay said today.
With the 35-year-old Manning recovering from a string of neck surgeries, Irsay released him two weeks ago rather than pay a $28 million bonus.
But plenty of teams still believed Manning has the ability to be the kind of leader who guided Indy to 12 wins a season from 2001-10.
Elway and company beat them all out. The man who led the Broncos to two Super Bowl titles in the late 1990s, and now serves as Denver's vice president of football operations, Elway never sounded all that convinced Tebow was the answer at the league's most important position. He could now trade the hugely popular quarterback, who energized the Broncos in a run to the playoffs last season but also was plagued by erratic play.
If so, expect the Broncos and Denver to be more upbeat about getting Manning than downcast over potentially losing Tebow.
"There's a lot to be excited about," Broncos defensive end Robert Ayers said Monday when asked about Manning. "Just being on his team is going to make you want to play better."
Although no starting QB has ever earned a Super Bowl ring for two different teams, every day at the Broncos' headquarters, Manning will at least see the two Lombardi Trophies in the lobby that Elway won — when he was 37 and 38.
Several Broncos predicted the free agency floodgates will swing wide open once Manning officially joins the team.
"I think we'll sign some guys, probably a few guys, like Dallas Clark, Jeff Saturday, guys waiting to see what Peyton was going to do," Ayers said. "Defensive guys want to play with a lead, and I'm pretty sure guys are going to assume Peyton will put up points in this offense, we have some weapons."
With Manning joining the Broncos, oddsmakers in Las Vegas immediately made Denver one of the top choices to win the Super Bowl next season, which will be played in Manning's hometown of New Orleans.
The Associated Press


text:
Terry heads the Mobile Library Services department and enjoys each and every one of the communities the bookmobile serves.
This is an official blog for the Marin County Free Library.
All branches of Marin County Free Library will be closed on Thursday, Nov 27 & Friday, Nov 28 for Thanksgiving.
Corte Madera Library will be closed for upgrades Nov 27 - Dec 15, reopening on Dec 16. More details.
Oh how I love to watch those seeds grow! I do wish my radishes would grow as fast as these but good things are worth waiting for and radishes are so.......well, dependable. If you like to grow things, check out these great books by Lois Ehlert:
And for everyone who's ever been in the school play or wanted to be, here's a great video of the "Plant a Radish, Get a Radish" song from the Fantasticks:


text:
Welcome to the UNFCCC Youth Constituency wiki!
It is time to play our part as young changemakers to influence an outcome that is best for the Earth, for humanity and for future generations.
The portal is wiki meant to provide detailed information on the year's activities, including the intersessionals, the Conference of Youths (COY) and the Conference of Parties (COP). This includes venues, activities, etc


text:
North Carolina Association of Realtors »
Another honor for realtor Rector
Share Phil Rector, broker/owner of Rector Realty, has received the prestigious Regional Service Award from the North Carolina Association of Realtors. The honor recognizes one outstanding realtor in each of 10 regions in theRead More »
Panel sees housing improvements
Share Local real estate professionals say they finally see some light at the end of what has been a very long tunnel. Professionals from across the Piedmont Triad attended Wharton Gladden's Second Annual NorthRead More »


text:
Privacy Policy
To be added to our interest list for the Global Justice Fellowship for Rabbis 2015, please fill out the information below and click "submit."
American Jewish World Service 45 West 36th Street New York, NY 10018
t: 212.792.2900 800.889.7146 f: 212.792.2930e: email@example.com
Site Map | For the Media | Contact Us | Privacy Policy | Jobs | Donate
© 2014 AJWS. All rights reserved.
Learn what you can do to participate in our work to end poverty and secure human rights in the developing world.


text:
Print Options
Back to
Spaghetti Pizza Casserole >
Full Page
Include these items:
Nutritional Facts
Select reviews >
Spaghetti Pizza Casserole
"I first tried this great-tasting dish at an office Christmas party. It quickly became everyone's favorite. It makes a wonderful alternative to ordinary spaghetti." —Kim Neer, Kalamazoo, Michigan
9 Servings
Prep: 25 min. Bake: 25 min.
1 package (7 ounces) spaghetti
1/2 cup egg substitute
1/4 cup grated Parmesan cheese
1 pound lean ground beef (90% lean)
1 medium onion, chopped
1/2 cup chopped green pepper
1/2 cup chopped sweet yellow pepper
2 garlic cloves, minced
1 jar (24 ounces) spaghetti sauce
1 teaspoon Italian seasoning
1 teaspoon dried basil
1/2 teaspoon salt
1/4 teaspoon pepper
1/2 pound sliced fresh mushrooms
1-1/2 cups (6 ounces) shredded part-skim mozzarella cheese
Cook spaghetti according to package directions. Drain and rinse with
cold water. In a large bowl, toss spaghetti with egg substitute and
Parmesan cheese. Spread evenly into a 15-in. x 10-in. x 1-in. baking
pan coated with cooking spray; set aside.
In a large nonstick skillet, cook the beef, onion and peppers over
medium heat until meat is no longer pink; drain. Add garlic; cook 1
minute longer. Stir in spaghetti sauce and seasonings; heat through.
Spoon over spaghetti. Top with mushrooms and mozzarella cheese. Bake,
© Taste of Home 2014
2 of 2
Spaghetti Pizza Casserole
Directions (continued)
uncovered, at 350° for 25-30 minutes or until lightly browned.
Let stand for 5 minutes before serving. Yield: 9 servings.
Nutritional Facts:
1 piece equals 274 calories, 8 g fat (4 g saturated fat), 37 mg cholesterol, 685 mg sodium, 29 g carbohydrate, 3 g fiber, 22 g protein.
Diabetic Exchanges:
2 lean meat, 1-1/2 starch, 1 vegetable.
Full-Bodied Red Wine: Enjoy this recipe with a full-bodied red wine such as
Cabernet Sauvignon
© Taste of Home 2014


text:
Thousands of spectators lined the streets of Roslyn last Saturday to witness an impressive display by fire departments from all throughout Long Island as they marched to pay tribute to the Roslyn Rescue Fire Company.
Summer is now in full swing and that means more people, especially more children out in the village streets. And so, Roslyn residents are expressing their concerns over traffic volume and road visibility on certain village thoroughfares. At its May meeting, the Village of Roslyn board of trustees approved a motion to install stop signs at various locations on Pool Drive. The signs were scheduled to be put in place on Monday, June 17.
On Monday, July 8, North Shore Child & Family Guidance Center will host its Annual 2002 Golf Classic and Tribute Dinner in honor of Kathleen O'Brien, vice president of U.S. Trust and Teresa Regnante, executive vice president of the United Way of Long Island. This fund-raising event will be held at the Engineers Country Club in Roslyn Harbor and will feature both golf and tennis packages as well as an evening cocktail hour, buffet dinner, and a sports memorabilia auction. The gold package is $450; tennis package if $225, and cocktails and dinner only is $150.
Ben Epstein of East Hills competed last weekend in the Copa Atlantica Brazilian Jiu-Jitsu Championships in Bayonne, NJ. Ben, a fifth grader at the Harbor Hills School, received a third place medal in the 90-99.9 lb. Division. He was the first child to represent the Serra Brazilian Jiu-Jitsu Academy in East Meadow in this prestigious tournament.
An Official Newspaper of the
LongIsland.Com Internet Community
antonnews.com home | Email the
Roslyn News|
Copyright ©2002 Anton Community Newspapers, Inc.All Rights Reserved.
LinkExchange Member