1. Firefox 4: An early walk-through of IndexedDB

    Web developers already have localStorage, which is used for client side storage of simple key-value pairs. This alone doesn’t address the needs of many web applications for structured storage and indexed data. Mozilla is working on a structured storage API with indexing support called IndexedDB, and we will have some test builds in the next few weeks. This can be compared to the WebDatabase API implemented by several browsers that uses a subset of the allowable language of SQLite. Mozilla has chosen to not implement WebDatabase for various reasons discussed in this post.

    In order to compare IndexedDB and WebDatabase, we are going to show four examples that use most parts of the asynchronous APIs of each specification. The differences between SQL storage with tables (WebDatabase) and JavaScript object storage with indexes (IndexedDB) becomes pretty clear after reading the examples. The synchronous versions of these APIs are only available on worker threads. Since not all browsers currently implement worker threads, the synchronous APIs will not be discussed at this time. The IndexedDB code is based off a proposal that Mozilla has submitted to the W3C WebApps working group that has gotten positive feedback so far. The code for both APIs does not include any error handling (for brevity), but production code should always have it!

    These examples are for the storage of a candy store’s sale of candy to customers, which we’ll refer to as kids. Each entry in candySales represents a sale of a specified amount of candy to a kid, specified by an entry in candy and kids respectively.

    Example 1 – Opening and Setting Up a Database

    This first example demonstrates how to open a database connection and create the tables or object stores if the version number is not correct. Upon opening the database, both examples check the version and create the necessary tables or object stores and then set the correct version number. WebDatabase is a bit stricter in how it handles versions by giving an error if the database version is not what the caller expects (this is specified by the second argument to openDatabase). IndexedDB simply lets the caller handle versioning as they see fit. Note that there is active discussion about how IndexedDB should handle version changes in the working group.

    WebDatabase

    var db = window.openDatabase("CandyDB", "",
                                 "My candy store database",
                                 1024);
    if (db.version != "1") {
      db.changeVersion(db.version, "1", function(tx) {
        // User's first visit.  Initialize database.
        var tables = [
          { name: "kids", columns: ["id INTEGER PRIMARY KEY",
                                    "name TEXT"]},
          { name: "candy", columns: ["id INTEGER PRIMARY KEY",
                                     "name TEXT"]},
          { name: "candySales", columns: ["kidId INTEGER",
                                          "candyId INTEGER",
                                          "date TEXT"]}
        ];
     
        for (var index = 0; index < tables.length; index++) {
          var table = tables[index];
          tx.executeSql("CREATE TABLE " + table.name + "(" +
                        table.columns.join(", ") + ");");
        }
      }, null, function() { loadData(db); });
    }
    else {
      // User has been here before, no initialization required.
      loadData(db);
    }

    IndexedDB

    var request = window.indexedDB.open("CandyDB",
                                        "My candy store database");
    request.onsuccess = function(event) {
      var db = event.result;
      if (db.version != "1") {
        // User's first visit, initialize database.
        var createdObjectStoreCount = 0;
        var objectStores = [
          { name: "kids", keyPath: "id", autoIncrement: true },
          { name: "candy", keyPath: "id", autoIncrement: true },
          { name: "candySales", keyPath: "", autoIncrement: true }
        ];
     
        function objectStoreCreated(event) {
          if (++createdObjectStoreCount == objectStores.length) {
            db.setVersion("1").onsuccess = function(event) {
              loadData(db);
            };
          }
        }
     
        for (var index = 0; index < objectStores.length; index++) {
          var params = objectStores[index];
          request = db.createObjectStore(params.name, params.keyPath,
                                         params.autoIncrement);
          request.onsuccess = objectStoreCreated;
        }
      }
      else {
        // User has been here before, no initialization required.
        loadData(db);
      }
    };

    Example 2 – Storing Kids in the Database

    This example stores several kids into the appropriate table or object store. This example demonstrates one of the risks that have to be dealt with when using WebDatabase: SQL injection attacks. In WebDatabase explicit transactions must be used, but in IndexedDB a transaction is provided automatically if only one object store is accessed. Transaction locking is per-object store in IndexedDB. Additionally, IndexedDB takes a JavaScript object to insert, whereas with WebDatabase callers must bind specific columns. In both cases you get the insertion id in the callback.

    WebDatabase

    var kids = [
      { name: "Anna" },
      { name: "Betty" },
      { name: "Christine" }
    ];
     
    var db = window.openDatabase("CandyDB", "1",
                                 "My candy store database",
                                 1024);
    db.transaction(function(tx) {
      for (var index = 0; index < kids.length; index++) {
        var kid = kids[index];
        tx.executeSql("INSERT INTO kids (name) VALUES (:name);", [kid],
                      function(tx, results) {
          document.getElementById("display").textContent =
              "Saved record for " + kid.name +
              " with id " + results.insertId;
        });
      }
    });

    IndexedDB

    var kids = [
      { name: "Anna" },
      { name: "Betty" },
      { name: "Christine" }
    ];
     
    var request = window.indexedDB.open("CandyDB",
                                        "My candy store database");
    request.onsuccess = function(event) {
      var objectStore = event.result.objectStore("kids");
      for (var index = 0; index < kids.length; index++) {
        var kid = kids[index];
        objectStore.add(kid).onsuccess = function(event) {
          document.getElementById("display").textContent =
            "Saved record for " + kid.name + " with id " + event.result;
        };
      }
    };

    Example 3 – List All Kids

    This example lists all of the kids stored in the kids table or the kids object store. WebDatabase uses a result set object which will be passed to the callback method provided after all rows have been retrieved. IndexedDB, on the other hand, passes a cursor to the event handler as results are retrieved. Results should come back faster, as a result. While not shown in this example, you can also stop iterating data with IndexedDB by simply not calling cursor.continue().

    WebDatabase

    var db = window.openDatabase("CandyDB", "1",
                                 "My candy store database",
                                 1024);
    db.readTransaction(function(tx) {
      // Enumerate the entire table.
      tx.executeSql("SELECT * FROM kids", function(tx, results) {
        var rows = results.rows;
        for (var index = 0; index < rows.length; index++) {
          var item = rows.item(index);
          var element = document.createElement("div");
          element.textContent = item.name;
          document.getElementById("kidList").appendChild(element);
        }
      });
    });

    IndexedDB

    var request = window.indexedDB.open("CandyDB",
                                        "My candy store database");
    request.onsuccess = function(event) {
      // Enumerate the entire object store.
      request = event.result.objectStore("kids").openCursor();
      request.onsuccess = function(event) {
        var cursor = event.result;
        // If cursor is null then we've completed the enumeration.
        if (!cursor) {
          return;
        }
        var element = document.createElement("div");
        element.textContent = cursor.value.name;
        document.getElementById("kidList").appendChild(element);
        cursor.continue();
      };
    };

    Example 4 – List Kids Who Bought Candy

    This example lists all the kids, and how much candy each kid purchased. WebDatabase simply uses a LEFT JOIN query which makes this example very simple. IndexedDB does not currently have an API specified for doing a join between different object stores. As a result, the example opens a cursor to the kids object store and an object cursor on the kidId index on the candySales object store and performs the join manually.

    WebDatabase

    var db = window.openDatabase("CandyDB", "1",
                                 "My candy store database",
                                 1024);
    db.readTransaction(function(tx) {
      tx.executeSql("SELECT name, COUNT(candySales.kidId) " +
                    "FROM kids " +
                    "LEFT JOIN candySales " +
                    "ON kids.id = candySales.kidId " +
                    "GROUP BY kids.id;",
                    function(tx, results) {
        var display = document.getElementById("purchaseList");
        var rows = results.rows;
        for (var index = 0; index < rows.length; index++) {
          var item = rows.item(index);
          display.textContent += ", " + item.name + "bought " +
                                 item.count + "pieces";
        }
      });
    });

    IndexedDB

    candyEaters = [];
    function displayCandyEaters(event) {
      var display = document.getElementById("purchaseList");
      for (var i in candyEaters) {
        display.textContent += ", " + candyEaters[i].name + "bought " +
                               candyEaters[i].count + "pieces";
      }
    };
     
    var request = window.indexedDB.open("CandyDB",
                                        "My candy store database");
    request.onsuccess = function(event) {
      var db = event.result;
      var transaction = db.transaction(["kids", "candySales"]);
      transaction.oncomplete = displayCandyEaters;
     
      var kidCursor;
      var saleCursor;
      var salesLoaded = false;
      var count;
     
      var kidsStore = transaction.objectStore("kids");
      kidsStore.openCursor().onsuccess = function(event) {
        kidCursor = event.result;
        count = 0;
        attemptWalk();
      }
      var salesStore = transaction.objectStore("candySales");
      var kidIndex = salesStore.index("kidId");
      kidIndex.openObjectCursor().onsuccess = function(event) {
        saleCursor = event.result;
        salesLoaded = true;
        attemptWalk();
      }
      function attemptWalk() {
        if (!kidCursor || !salesLoaded)
          return;
     
        if (saleCursor && kidCursor.value.id == saleCursor.kidId) {
          count++;
          saleCursor.continue();
        }
        else {
          candyEaters.push({ name: kidCursor.value.name, count: count });
          kidCursor.continue();
        }
      }
    }

    IndexedDB generally simplifies the programming model for interacting with databases, and allows for a wide number of use cases. The working group is designing this API so it could be wrapped by JavaScript libraries; for instance, there’s plenty of room for a CouchDB-style API on top of our IndexedDB implementation. It would also be very possible to build a SQL-based API on top of IndexedDB (such as WebDatabase). Mozilla is eager to get developer feedback about IndexedDB, particularly since the specification has not been finalized yet. Feel free to leave a comment here expressing your thoughts or leave anonymous feedback through Rypple.

  2. Firefox 4: CSS3 calc()

    This article describes the CSS3 calc() value. This feature hasn’t landed yet in any Firefox tree but work to implement it is underway.

    Firefox will support the CSS calc() value, which lets you compute a length value using an arithmetic expression. This means you can use it to define the sizes of divs, the values of margins, the widths of borders, and so forth.

    Here is an example of a layout which would be tricky to setup without the calc() function:

    /*
    * Two divs aligned, split up by a 1em margin
    */
    #a {
      width:75%;
      margin-right: 1em;
    }
    #b {
      width: -moz-calc(25% - 1em);
    }

    This example makes sure an input text field won’t overlap its parent:

    input {
      padding:2px;
      border:1px solid black;
      display:block;
      width: -moz-calc(100% - 2 * 3px);
    }

    One particularly powerful feature of the calc() function that you can combine different units in the same computation:

    width: -moz-calc(3px + 50%/3 - 3em + 1rem);

    The current implementation supports the +, -, *, /, mod, min, and max operators.

    We’ll also support the min() and max() functions, which could be used like this:

    div {
      height: -moz-min(36pt, 2em);
      width: -moz-max(50%, 18px);
    }

    For more details, see:

  3. Beyond HTML5: Database APIs and the Road to IndexedDB

    IndexedDB is an evolving web standard for the storage of significant amounts of structured data in the browser and for high performance searches on this data using indexes. Mozilla has submitted substantial technical feedback on the specification, and we plan to implement it in Firefox 4. We spoke to prominent web developers about evolving an elegant structured storage API for the web. While versions of Safari, Chrome, and Opera support a technology called Web SQL Database, which uses SQL statements as string arguments passed to a JavaScript API, we think developer aesthetics are an important consideration, and that this is a particularly inelegant solution for client-side web applications. We brought developer feedback to the editor of the IndexedDB specification, and also spoke with Microsoft, who agree with us that IndexedDB is a good option for the web. With additional implementations from the Chrome team in the offing, we think it is worth explaining our design choices, and why we think IndexedDB is a better solution for the web than Web SQL Database.

    Web applications can already take advantage of localStorage and sessionStorage in IE 8+, Safari 4+, Chrome 4+, Opera 10.5+ and Firefox 2+ to store key-value pairs with a simple JavaScript API. The Web Storage standard (encompassing localStorage and sessionStorage), now widely implemented, is useful for storing smaller amounts of data, but less useful for storing larger amounts of structured data. While many server-side databases use SQL to programmatically store structured data and to meaningfully query it, on the client-side, the use of SQL in a JavaScript API has been contentious.

    SQL? Which SQL?

    Many web developers certainly are familiar with SQL, since many developers touch just as much server-side code (e.g. PHP and database operations) as client-side code (e.g. JavaScript, CSS, and markup). However, despite the ubiquity that SQL enjoys, there isn’t a single normative SQL standard that defines the technology. In particular, SQLite supports most of SQL-92, with some notable omissions, and is what the WebDatabase API is based on. But SQLite itself isn’t a specification — it’s a release-ready technology! And the best definition of what constitutes the supported subset of SQL that SQLite uses is the SQLite manual. In order to really get Web SQL Database right, we’d have to first start with defining a meaningful subset of SQL for web applications. Why define a whole other language, when more elegant solutions exist within JavaScript itself?

    The Benefits and Pitfalls of SQLite

    We think SQLite is an extremely useful technology for applications, and make it available for Firefox extensions and trusted code. We don’t think it is the right basis for an API exposed to general web content, not least of all because there isn’t a credible, widely accepted standard that subsets SQL in a useful way. Additionally, we don’t want changes to SQLite to affect the web later, and don’t think harnessing major browser releases (and a web standard) to SQLite is prudent. IndexedDB does not have this problem; even though our underlying implementation of IndexedDB may be based on SQLite, we keep developers insulated from changes to SQLite by exposing an API that isn’t based on SQLite’s supported syntax.

    Aesthetics and Web Developers

    Last year, we held a summit at the Mozilla campus to discuss storage on the web. We invited web developers to speak to us about a desirable structured storage API on the web. Many did express resigned acceptance of a SQLite-based API, since they had already experimented with releases of Web SQL Database in some browsers, and claimed that something in circulation was better than a collection of ideas. Yet, all voiced enthusiasm for better design choices, and how a simpler model would make life easier for them. We watched as developers whiteboarded a simple BTree API that addressed their application storage needs, and this galvanized us to consider other options. We were resolved that using strings representing SQL commands lacked the elegance of a “web native” JavaScript API, and started looking at alternatives. Along with Microsoft, we sent feedback about the IndexedDB proposal and actively became involved in the standardization effort.

    In another article, we compare IndexedDB with Web SQL Database, and note that the former provides much syntactic simplicity over the latter. IndexedDB leaves room for a third-party JavaScript library to straddle the underlying primitives with a BTree API, and we look forward to seeing initiatives like BrowserCouch built on top of IndexedDB. Intrepid web developers can even build a SQL API on top of IndexedDB. We’d particularly welcome an implementation of the Web SQL Database API on top of IndexedDB, since we think that this is technically feasible. Starting with a SQL-based API for use with browser primitives wasn’t the right first step, but certainly there’s room for SQL-based APIs on top of IndexedDB.

    We want to continue the discussion with web developers about storage on the web, since that helps us structure our thoughts about product features and future web standards. We look forward to seeing the next generation of web applications with support for high performance searches on indexed data, and to seeing web applications work even more robustly in “airplane mode.”

    Links

  4. HTML5 adoption stories: box.net and html5 drag and drop

    This is a guest post from Tomas Barreto, a developer who works at box.net. They recently adopted HTML5 drag and drop as a way to share files with other people using new features in Firefox. The included video is a pitch for the feature and service, but shows how easy it is to do simple HTML5-based upload progress even with multiple files. Tomas gives an overview of the relatively simple JavaScript required to do this, and how improvements in Firefox 4 will make things even easier. Also have a quick look at the bottom of the post for links to additional docs and resources.

    At Box.net, we’re always exploring new ways to help users get content quickly and securely onto our cloud content management platform. So when asked, “What feature would make you use Box more?” during the Box Hack Olympics in April, my colleague CJ and I decided to tackle the most intuitive way to upload files: simply dragging them from the desktop into Box.

    We considered technologies ranging from Gears to Firefox plugins, but only HTML5 had sufficient adoption. By using some of the JavaScript APIs defined in the HTML5 standard, CJ and I could create a seamless drag and drop experience for our users on supporting browsers. Furthermore, using an HTML5-based upload feature would allow us to enable users to select multiple files at once, and also display progress on the client without polling. And with HTML5 adoption across the latest versions of three of the top four browsers, we felt confident about building an upload method based on this new technology without the trade-offs of using a third-party plug-in.

    We rolled out the first rev of our drag and drop feature a few weeks ago, and we’re impressed with how quickly it has been adopted. It’s already one of the most popular ways to get files onto Box, and in its first week it surpassed our old AJAX upload method. You can check out our demo video to get a feel for the feature:

    To build this feature, we referenced a handful of online examples that explained how to use Firefox 3 FileReader object and the drag and drop file event support. Our first implementation used this object to load the file into memory and then took advantage of the latest XMLHttpRequest events to track progress on the client.

    var files = event.originalEvent.dataTransfer.files; // drop event
    var reader = new FileReader();
     
    reader.onload = function(event) {
      var file_contents = event.target.result;
      var request = new XMLHttpRequest();
     
      ... // attach event listeners to monitor progress and detect errors
     
      var post_body = '';
     
      .. // build post body
     
      post_body += file_contents;
     
      .. // finish post body
     
      var url = 'http://example.com/file_upload';
     
      var request = new XMLHttpRequest();
     
      request.open("POST",  url, true); // open asynchronous post request
      request.setRequestHeader('content-type', 'multipart/form-data; boundary=""'); // make sure to set a boundary
      request.send(post_body);
    }
     
    reader.readAsBinaryString(files[0]);

    This approach worked well because we could use the same server processing code that we previously used for uploads. The main disadvantage here is that the FileReader object reads the entire file into memory, which is not optimal for a general upload use case. Our current HTML5 implementation uses this logic and has forced us to restrict drag and drop uploads to just 25mb. However, thanks to recommendations from the Mozilla team, we’ll be taking an alternative approach for V2 of drag and drop, where the file is read chunks as needed by the request. Here’s how we’re going to do it:

    var files = event.originalEvent.dataTransfer.files; // drop event
    var url = 'http://example.com/file_upload';
     
    var request = new XMLHttpRequest();
    request.open("POST",  url, true); // open asynchronous post request
    request.send(files[0]);

    Since this approach is not formatted as a multipart form-data, it will require some adjustments on our back-end to support receiving file uploads in this way. However, it’s definitely worth the trade-off since we’ll get all the benefits of the previous method and we don’t need special file size restrictions. In the future, we’ll consider using yet another way to efficiently upload files that is supported in Firefox 4 and uses the traditional multi-part form:

    var files = event.originalEvent.dataTransfer.files; // drop event
    var url = 'http://example.com/file_upload';
     
    var request = new XMLHttpRequest();
     
    var fd = new FormData;
    fd.append("myFile", files[0]);
     
    request.open("POST",  url, true); // open asynchronous post request
    request.send(fd);

    We’re already exploring more ways to enrich the Box experience using HTML5. With HTML5, we can build faster, richer and more interactive features with native browser support, and bridge the traditional gap between desktop software and web applications. Here are just a few cool new upload-related features on our roadmap:

    • Pause/Resume uploads using the Blob slice API to split files into chunks (this will be a huge robustness boost, especially for large uploads)
    • Allowing uploads to resume even after the browser closes by caching the file using IndexedDB support (possibly in Firefox 4)

    We’d also like to begin a discussion about supporting the reverse drag and drop use case: dragging files from the browser to the desktop. Based on our users’ enthusiasm around the drag and drop upload feature, we think the reverse functionality would well received. If you are interested in contributing to a specification for this feature, please let us know (html5 [-at$] box.net)!

    Resources:

  5. Results from our Developer Survey #2

    To follow up on the developer survey from last November, we did a second survey this past March after the releases of Firefox 3.6 and Firebug 1.5 to gauge developer reactions to the latest features in the browser and a much improved version of everyone’s favorite developer tool.

    In this post we’ll share the results of our latest survey and provide some data and insights from all the great feedback we have received.  We hope this will help us better understand developers’ needs and continue to build out the Mozilla Developer Network to better engage with them.

    Recap of the November 2009 Survey

    As a refresher, here is a summary of the initial November 2009 survey. The main takeaways were as follows:

    • Our community is made up of a diverse set of developers that cover all aspects of web development from design to back-end work.
    • Open standards are by far the most popular technologies used for web development work.
    • Firefox is the most common browser used first by developers for testing their work, primarily because of the many developer tools and Add-ons available for Firefox and Mozilla’s strong support for web standards.
    • Firebug stood out as the most popular developer tool and many developers agreed that it is “absolutely essential for development.”

    Results from the March 2010 Survey

    Our second developer survey received 2,267 responses over two months from late March to early June.

    For this survey there were several common questions from the previous one  – about browser preferences – so that we could measure satisfaction over time and follow trends in browser adoption following the release of Firefox 3.6.
    We also responded to the overwhelmingly enthusiastic praise of Firebug by asking for feedback on the most recent release.  By obtaining more specific feedback on the latest version of Firebug, we hope to address any remaining issues to make it an even more effective and attractive tool for developers.

    Developer Browser Preferences

    We did not see much change in browser preferences from November 2009 to March 2010.  Even considering a new iteration of Firefox and increasing competition from other browsers, the data still reflect general browser market share trends: the latest versions of Firefox and Chrome gained at the expense of older versions of IE.

    The following data show the primary browsers developers use to test their websites:

    Which browser(s) do you test your web sites against to make sure they are compatible?

    November 2009


    Tested Against
    Percent
    Firefox 3.5 82.03%
    IE 8 74.63%
    IE 7 68.23%
    Chrome 60.23%

    March 2010

    Tested Against Percent
    Firefox 3.6 80.17%
    IE 8 70.23%
    Chrome 62.37%
    IE 7 56.18%

    The numbers are unlikely to shift drastically because regardless of developers’ personal preferences, the top browsers listed above are the ones most commonly used by regular users, as demonstrated by browser market share data. Thus it makes sense that developers test against these browsers most often.

    Firefox isn’t just the most popular browser for developing, according to the data below; it’s also popular for personal usage. It should be noted, however, that this survey was distributed primarily though Mozilla-related channels, so there might be some bias in the results; we address this problem later in the report.

    Note also that the vast majority of developers were quick on the uptake switching from 3.5 to 3.6.

    Have you tried Firefox 3.6?

    Upgrading to Firefox 3.6

    Although the vast majority of developers switched from 3.5 to 3.6, there were still some who did not. In fact, roughly 10% of the March survey respondents still used 3.5. The primary reasons for the continued usage on 3.5, however, had little to do with personal preference. Roughly half of those who still used 3.5 did not even know that 3.6 was released, while the other half responded that they didn’t have time to update.

    One interesting note from the results was that a lot of developers still using Firefox 3.5 were on Linux distros that did not yet have the Firefox 3.6 package available at the time they took the survey.  Given that 23% of respondents develop on the Linux platform, that could explain why so many had not made the jump.

    What operating system do you mainly use for your development environment?

    Unfortunately the data lacked specific details on why developers did not know about 3.6 or why they did not find time to update to the next version.  With that said, regardless of the reasons, it is clear we should focus on facilitating the update process for future iterations of Firefox.  We will start by promoting early betas and announcing new Firefox releases on the MDN website.

    Feedback on Firebug 1.5

    We all know that Firebug is important to developers, so we wanted to focus on getting Firebug-related feedback for this survey. Comments about Firebug echoed those from the November survey: the consensus is that “Firebug is the single most important tool in web development.” Indeed Firebug is considered such a critical tool in the developer’s arsenal that several of you asked us to package Firebug as a built-in component of Firefox instead of just as an Add-on; some users call the duo the “triple F”: Firefox and Firebug.

    While the 1.5 release was a huge improvement from previous versions, developers weren’t shy about sharing their frustrations and feature requests.  Many noted occasional stability issues, such as when Firebug is finding elements in document trees or taking certain Ajax requests. Additionally, we received several suggestions for improving the user interface, such as incorporating more Firefox-native design elements, increasing the size of the “Deactivate Firebug” button, and removing elements like the “Quick Info” and “CSS Overview” boxes.

    One data point that stood out was that about 22% of developers had not tried Firebug 1.5 at the time they took the survey.  Considering that it was released in January and the survey was open from March to June, we would have expected that the adoption of such an important tool to be higher than what the data suggests.  This presents an opportunity to better communicate new releases and raise awareness among developers to make sure they are up-to-date on the latest development happening with Firebug.

    Have you tried Firebug 1.5?

    For those of you who are interested in learning more about documentation, features, and related news, visit the Firebug website.  Along with regular blog posts from the team, the site will host community forums for discussions with community and Firebug team members and offer ways to get involved if you want to contribute to the project.  Firebug 1.6 development is well underway and we’ll continue to see it evolve to meet web developers’ needs.

    Next Steps

    Thus far your feedback via our first two surveys has been invaluable as we strive to build a better open Web through the Mozilla Developer Network.  We now have a decent snapshot of the type of development you do, the technologies and tools you use, and the browsers you prefer for both work and personal use.  The insights we have gained will help us refine the MDN roadmap and guide the programs we develop over of the next year to better engage with developers and build out the MDN website to meet your needs.

    Our next step is to move beyond these initial data to get a larger snapshot of the developer community. We will start by designing an informal survey to get a grasp of what developers here at Mozilla and within our immediate community have to say about the tools and resources they find the most valuable for their work.  We plan to follow that up with more research on the web developer community as a whole by distributing an industry-wide survey.

    The goal for Q3 is to design a survey that can be distributed to a more diverse and unbiased global developer community.   Ultimately our goal is to have the clearest possible picture of the global web developer community and how it views the current “state of the Web”.