Wednesday, March 11, 2015
But does it work an agile metric
After implementing several changes to our process, my projects over the years seem to have improved significantly. But how do you measure this? While no metric should stand alone, here is one quality metric that Im experimenting with:
((# of high defects * 5) + (# of medium defects * 3) + (# of low defects * 1) / Total project hours * 100.
The troubled project had a score of 18.7. My most recent project score was 1.2 which is almost a 1600% improvement on quality. I think Ill keep doing this agile thing.
P.S. Im heading to Agile2010 this summer. Give me a shout if you are going and we can find ways to de-brief together over lunch or dinner in Orlando.
Announcing the Google Drive Installation Scope
Not long after the Drive SDK was first released, we started receiving requests for a simpler developer and user experience. It took too long for developers to get started, and users were sometimes confused by the ways apps were installed. We’re now announcing a new feature that helps address these concerns: the Drive installation scope.
As the name suggests, this new OAuth 2.0 scope lets users install an app by approving an access request. Along with all the other levels of access you can request from users, it’s now possible to ask users for permission to install your app in their Drive.
This means that an app, or an app’s promotion page, could present an option to “Install this app in Google Drive,” and then users who select this option would interact with an OAuth 2.0 dialog that requests the installation scope. For example, the following script creates an “Add to Google Drive” button that could be embedded in a web page:
<script src="https://apis.google.com/js/client.js"></script>
<script>
var CLIENT_ID = 123456789.apps.googleusercontent.com
function installDriveApp() {
gapi.auth.authorize({
client_id: CLIENT_ID,
scope: https://www.googleapis.com/auth/drive.install,
immediate: false
}, function(authResult) { // Callback when installation complete });
}
</script>
<button onclick="installDriveApp();">Add to Google Drive</button>
On clicking this button, the user sees a standard OAuth 2.0 dialog box like the following (text for the installation scope is expanded in this example):
When the user approves these scopes, the app is installed for the user. Then, once it is installed this way, the app appears in the user’s Open with options as well as the Create > more contextual menu for files of registered MIME types.
Apps still need to specify primary and secondary MIME types when they enable the Drive SDK in the APIs console. But, unlike before, there is no need to install via the Chrome Web Store in order to get UI integration -- web store integration is entirely optional (though recommended).
Essentially, Drive now offers three levels of integration, which apps can combine according to their needs:
- Simple API access with the Drive API enabled.
- UI integration, with API access, the Drive SDK enabled, and OAuth-based installation.
- CWS-based integration, with all of the above plus web store installation and marketing/upsell features.
For guidance in getting started integrating your app in any of these ways, see “Build a Drive Web App” or "Integrate with the Drive UI" in the SDK documentation.
We still recommend that developers consider the many benefits of creating a Chrome Web Store listing for their application. In addition to providing ease of installation for users “shopping” in the Drive app collection, a web store listing provides helpful features to market and promote an app. Our usage analysis shows that apps in the Chrome Web Store receive more usage than apps that aren’t listed. But now, with the installation scope, you can get started developing and testing your app more quickly and then list it in the Chrome Web Store when you’re ready.
If you have any questions about the installation scope, don’t hesitate to let us know on our Stack Overflow tag, google-drive-sdk.
![]() | Eric Gilmore Eric is a technical writer working with the Developer Relations group. Previously dedicated to Google Apps APIs, he is now busy writing about all aspects of the Google Drive SDK. |
Using open source libraries in Apps Script
JavaScript has long been the de facto choice for client-side web development, but lately its been catching on server-side as well. While we like to think that Apps Script has contributed to the trend, projects such as Mozillas Rhino and Node.js have also done a great deal to popularize the concept. As a result, developers have created a wealth of new open-source JavaScript libraries, and in this post well talk about how you can leverage them in your Apps Script projects.
Underscore
One library I wanted to use in my scripts was Underscore, which describes itself as "a utility-belt library for JavaScript." It provides a wealth of helper functions that make coding in JavaScript cleaner and more enjoyable. Take, for example, the simple situation where you want to log each value in a range.
// Using plain JavaScript.
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
Logger.log(values[i][j]);
}
}
Although writing for loops like this is a common pattern, its a fair amount of typing and you need to keep track of counter variables that serve little purpose. Underscore provides an each() method that makes the process much simpler.
// Using Underscore.
_.each(values, function(row) {
_.each(row, function(cell) {
Logger.log(cell);
});
});
Passing anonymous functions as parameters takes a little getting used to, but if youve worked with jQuery, the pattern feels familiar.
Underscore also has some great extensions, and Underscore.string provides some useful string manipulation features. My favorite is the ability to use sprintf() notation in JavaScript, which can simplify the process of building complex strings.
// Using plain JavaScript.
var message = "Hello, " + firstName + " " + lastName + ". Your wait time is " + wait + " minutes.";
// Using Underscore.string.
var message = _.sprintf("Hello, %s %s. Your wait time is %d minutes.", firstName, lastName, wait);
Integrating with Apps Script
The simplest way to include the Underscore library in a project would be to paste its source code directly into your script, but this would lead to a lot of duplication if you end up using it in multiple projects. Earlier this year, we released a feature in Apps Script called libraries that allows you to share scripts and include them in other projects. Packaging a JavaScript library like Underscore as an Apps Script library is possible, but requires some helper functions to work correctly.
When Underscore loads, it creates a global variable named "_" that you use to access its functionality. Apps Script specifically prevents the global scope of a library from interfering with the global scope of the script that includes it, so I built a helper function into the library to pass the variable around.
// In the library.
function load() {
return _;
}
In my script that includes the library, I simply make a call to that function and use the result to set up my own "_" variable.
// In the script that includes the library.
var _ = Underscore.load();
To try my copy of the Underscore library in your own project, use the project key "MGwgKN2Th03tJ5OdmlzB8KPxhMjh3Sh48" and the code snippet above. You can browse the full source code here.
Using it with the HtmlService
Using the code above, I could easily include the library in my server-side Apps Script code, but I also wanted to use these functions client-side in my web app served by the HtmlService. To accomplish this, I created a copy of the Underscore source code, wrapped it in <script> tags, and stored them in Html files (instead of Script files). These snippet files could then be included in my web apps HtmlTemplates using the helper function below.
// In the library.
var FILES = [Underscore.js, Underscore.string.js, Init.js];
function include(output) {
for (var i = 0; i < FILES.length; i++) {
var file = FILES[i];
output.append(
HtmlService.createHtmlOutputFromFile(file).getContent());
}
}
This function was called in the web apps HtmlTemplate using the simple code below.
<!-- In the web app that includes the library. -->
<html>
<head>
<? Underscore.include(output) ?>
</head>
...
Other libraries
Integrating with Underscore was fairly easy, but trying the same approach with other open-source libraries may be a bit more complicated. Some libraries wont run correctly in the Apps Script environment if they rely on certain capabilities within the browser or Node.js runtime. Additionally, to be served by the HtmlService, the code must pass the Caja engines strict validation, which many popular libraries dont meet. In some cases, you may be able to manually patch the library to work around these issue, but this usually requires a deep understanding of how the library works.
We hope youre inspired to use Underscore and other open-source libraries in your own work. If you find a library that works great with Apps Script, share it with me on Google+ and Ill help get the word out.
![]() | Eric Koleda profile Eric is a Developer Programs Engineer based in NYC on the Google Apps Script team. Hes previously worked with the AdWords API and enterprise content management software. |
Google Groups and Google Apps Script
Google Groups is a great way to foster communication over email and on the web, connecting people and allowing them to participate in and read archived discussions. Today, we are introducing the Google Groups Service in Google Apps Script. Groups Service will allow a script to check if a user belongs to a certain group, or to enumerate the members of a particular group. The Google Groups Service works with groups created through the Google Groups web interface as well as groups created by enterprise customers with their own domain using the control panel and the Google Apps Provisioning API.
This opens a wide range of possibilities, such as allowing a script with Ui Services to show additional buttons to the members of a particular group - for example teachers or managers - and sending customized emails to all the members of a group.
Here are a few sample scripts to help you get started with the new API. To try out these samples, select Create > New Spreadsheet and then Tools > Script Editor from the menu. You can then copy the code into the script editor. The scripts’ output will appear back in the spreadsheet.
List Your Google Groups
The Groups Services can be used to fetch a list of the Google Groups of which you’re a member.
Below is a function which returns all the groups of which you’re a member. Copy and paste it into the script editor and run it. The editor will prompt you to grant READ access to the Google Groups Service before the script can run successfully.
If you receive a message stating that you’re not a member of any group, open up Google Groups and join any of the thousands of groups there.
function showMyGroups() {
var groups = GroupsApp.getGroups();
var s;
if (groups.length > 0) {
s = "You belong to " + groups.length + " groups: ";
for (var i = 0; i < groups.length; i++) {
var group = groups[i];
if (i > 0) {
s += ", ";
}
s += group.getEmail();
}
} else {
s = "You are not a member of any group!";
}
Browser.msgBox(s);
} Test Group Membership
Brendan plays trumpet in a band. He also runs the band’s website and updates its Google+ page. He’s created a web application with Google Apps Script and now he wants to add to it some additional features for members of the band. Being a model Google user, he’s already subscribed each band member to a Google Group. Although building a complete UI with Google Apps Script is beyond the scope of this article, Brendan could adapt the following function to help make additional features available only to members of that Google Group.
Of course, this is not just useful for tech-savvy trumpet players: schools may wish to make certain features available just to teachers or others just to students; businesses may need to offer certain functionality to people managers or simply to show on a page or in a UI operations of interest to those in a particular department. Before running this example yourself, replace test@example.com with the email address of any group of which you’re a member.
Note: the group’s member list must be visible to the user running the script. Generally, this means you must yourself be a member of a group to successfully test if another user is a member of that same group. Additionally, group owners and managers can restrict member list access to group owners and managers. For such groups, you must be an owner or manager of the group to query membership.
function testGroupMembership() {
var groupEmail = "test@example.com";
var group = GroupsApp.getGroupByName(groupEmail);
if (group.hasUser(Session.getActiveUser().getEmail())) {
Browser.msgBox("You are a member of " + groupEmail);
} else {
Browser.msgBox("You are not a member of " + groupEmail);
}
} Get a List of Group Members
Sending an email to the group’s email address forwards that message to all the members of the group. Specifically, that message is forwarded to all those members who subscribe by email. Indeed, for many users, discussion over email is the principal feature of Google Groups.
Suppose, however, that you want to send a customised message to those same people. Provided you have permission to view a group’s member list, the Google Groups Service can be used to fetch the usernames of all the members of a group. The following script demonstrates how to fetch this list and then send an email to each member.
Before running this script, consider if you actually want to send a very silly message to all the members of the group. It may be advisable just to examine how the script works!
function sendCustomizedEmail() {
var groupEmail = "test@example.com";
var group = GroupsApp.getGroupByEmail(groupEmail);
var users = group.getUsers();
for (var i = 0; i < users.length; i++) {
var user = users[i];
MailApp.sendEmail(user.getEmail(), "Thank you!",
"Hello " + user.getEmail() + ", thank you for joining this group!");
}
} Find Group Managers
The Google Groups Service lets you query a user’s role within a group. One possible role is MANAGER (the other roles are described in detail in the Google Groups Service’s documentation): these users can perform administrative tasks on the group, such as renaming the group and accepting membership requests. Any user’s Role can be queried with the help of the Group class’ getRole() method.
This sample function may be used to fetch a list of a group’s managers. Once again, you must have access to the group’s member list for this function to run successfully:
function getGroupOwners(group) {
var users = group.getUsers();
var managers = [];
for (var i = 0; i < users.length; i++) {
var user = users[i];
if (group.getRole(user) == GroupsApp.Role.MANAGER) {
managers.push(user);
}
}
return managers;
} Let us know what you end up building, or if you have any questions about this new functionality, by posting in the Apps Script forum.
![]() | Trevor Johnston Trevor is a software engineer at Google. Before joining the Google Apps Script team in New York, he developed travel products in Switzerland and supported Google’s help centers in Dublin. Prior to joining Google, he worked on Lotus branded products at IBM’s Dublin Software Lab. |
Important Changes to Google Apps Marketplace Billing Policies
When we launched the Google Apps Marketplace in March last year, one of our goals was to make it easy for developers to build, integrate, and sell their apps to Google Apps users. Since then, each vendor in the Google Apps Marketplace has handled their own billing and keeps the revenue they generate. Today, we are making that the official Marketplace policy moving forward: Google will not require vendors to adopt a Google billing API or share any portion of their revenue with us. This will keep more revenue in developers’ pockets, and brings the Google Apps Marketplace policy in line with the Chrome Web Store.
So it’s business as usual -- developers can continue to “bring their own billing” to the Marketplace. Developers retain full control over application pricing and billing, and continue to keep all revenue from Google Apps Marketplace customers.
If you’re in need of a billing solution, we encourage you to try Google Checkout and In-App Payments. Or use one of the many other commercial billing and subscription services available online.
Please join us at our next Google Apps Developer Office Hours on Google+ Hangouts on December 19th at 12 PM PST time to discuss the Google Apps Marketplace and any questions you may have about these changes.
| Scott McMullan profile | twitter Scott is a Product Manager at Google, where he runs the Apps Marketplace and is extremely lucky to be able to work with amazing developers and companies revolutionizing the way businesses use the web. |


