<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 4/21/17 10:45 PM, Ben Bucksch wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com">
      <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
      <ul>
        <li>Gecko (mostly for historical reasons)<br>
          JS in Gecko is obviously fairly advanced<br>
        </li>
      </ul>
    </blockquote>
    I distinguish between two different subsets of Gecko: xpcshell and
    web app (i.e., do you get window as your global or do you get
    Components on the global?). For backend code, the distinction
    matters.
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com">
      <ul>
        <li>type checks. Not there yet, I think. Could use TypeScript,
          but that has other drawbacks. Can emulate type checks with
          "assert(foo instanceof Foo);" at the start of public
          functions, as poor man's type checks. Hopefully we'll get them
          with later JS engines. => EMULATE</li>
      </ul>
    </blockquote>
    I don't think there's any proposal to add any sort of optional types
    to JS itself. That means that we're going to need rely on linting
    tools or extraneous compilers--I don't think relying on dynamic type
    assertions are sufficient or decently motivating for adding strong
    typing: you'll want some sort of static tool. The advantage of
    Typescript is that it's reasonably standardized and well-supported,
    the disadvantage is that it is going to lag behind in JS support and
    it requires a transpilation step.
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com">
      <ul>
        <li>modules. Missing in language. But we have require() from
          npm. Easy to use, works well, and gives us easy access to tons
          of code from npm. I don't see that a native module system
          would gain us a lot on top of that. If native modules come
          later, and it's better, and it's integrated with npm, we can
          still switch to it => EMULATE</li>
      </ul>
    </blockquote>
    <br>
    There's a few subtly different kinds of module support (particularly
    when async module loading might come into play). Something like
    <a class="moz-txt-link-rfc2396E" href="https://github.com/umdjs/umd/tree/master/templates"><https://github.com/umdjs/umd/tree/master/templates></a> ends up
    coming up, and it would be very important, I think to standardize on
    the kind of module wrapper that ends up getting used.<br>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com">
      <ul>
      </ul>
      <br>
      I agree we need that. But with measure. You can easily spend
      40-80% of the coding time on tests alone. I know I have, in some
      projects. Writing tests should not need more than 20% of coding
      time, or actually 0% more (see below). To achieve that, the test
      suite needs to be very comfortable to work with.<br>
      <br>
      My measure would be: If you want to test your code, instead of
      opening the UI in every coding iterating, write a little test
      function that calls your function, and run that. Essentially, you
      save yourself the time of clicking through the UI every time, and
      instead use that same time to write the test. But no more. You do
      not write tests just for the sake of tests.<br>
      <br>
      I can't emphasize enough how important it is to get the right
      measure here. Wrong emphasis, and the project takes 5 times as
      long, i.e. 15 years instead of 3 years. I've seen that happen. If
      we do that, we won't finish.<br>
    </blockquote>
    <br>
    The best guideline I've heard for writing tests is that the point of
    tests is to fail--if you expect a test is not going to fail by a
    plausible changeset, then you are wasting time with that test. You
    also want to avoid writing tests that will break if you do something
    reasonable but minor (I am guilty of this); an example of such a
    fragile test is test_attachment_intl.js, which I have personally
    spent far more time fixing than it has identified bugs. One remedy
    for the latter is spending time to actually curate your test suite
    and give developers better test assertions than "test thing A is
    equal to thing B."<br>
    <br>
    While I agree that achieving 100% test coverage is a fools' errand
    for the most part, I think there is a high value of making sure that
    test coverage is reasonably complete. In particular, if you're
    fixing a bug, there should be an a priori assumption that a test
    needs to be written for that fix (one that fails before the patch
    and succeeds after it).<br>
    <br>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com"> Yes.
      Many projects are inherently a complete system, e.g.
      client/server. Ours is not - we're an email *client*. We interact
      with servers not under our control, but our users totally depend
      on the functioning of our client with these servers. We cannot
      allow even one day of gmail.com IMAP not working. Right now, we
      rely on anecdotal bug reports, and it takes time until we realize
      that the server changed. That needs to change.<br>
      <br>
      I'd like an "integration" test suite that tests our components
      (not UI), but with real-world servers. We'll set up test accounts
      at all ISPs that have more than 1% market share among our users.
      Then we regularly run tests (at least every 6 hours or so, and
      after every commit) on all of these accounts, whether log in
      works, whether I get notified of new mail (IMAP IDLE/push), I can
      fetch emails, send emails, copy mails etc.. If that fails without
      code change, we know immediately something changed at e.g. Gmail.
      If that fails after a code change, we know we broke e.g. Yahoo.<br>
      <br>
      I think this high-level integration test is far more important for
      Thunderbird users than classic unit tests on artificial local test
      servers. We'd test what the users actually use. We'd implicitly
      test all the code that's actually run when users use TB. And it's
      much faster to write, because one high-level function triggers a
      lot of low-level code.<br>
    </blockquote>
    <br>
    The problem with integration tests is that, as a developer, I never
    want to run them, since they're slow. Their value for doing quick
    sanity checks during many types of bug fixing is then rather
    minimal, particularly in comparison with low-level protocol unit
    tests. The further problem with the kinds of tests you're proposing
    is that they are completely unusable for developers. Now having
    automated tests against real servers can be useful, but they can't
    be the primary tests that we rely on for functionality.<br>
    <br>
    Now, that said, I think the fakeservers are a mistake, in
    retrospect. The original goal was to be able to easily and quickly
    mimic certain server setups to test specific scenarios, but the
    amount of implementation work to be able to get them to that point
    is simply staggering. We have better tools now to let people test
    against actual server implementations even in a completely sandboxed
    environment. I think that establishing tests against a few open
    source server implementations with common data setups in Docker
    containers is the best way to test these components (I even have a
    repository somewhere that stuffs OpenLDAP and Dovecot in a docker
    container), combined with a smattering of mock tests that involve
    explicitly feeding expected data to test things that need really
    specific network conditions (we have had a few bugs in the past that
    depended on "this literal ends on a specific packet boundary," which
    isn't really testable without this kind of test), probably with a
    very thin layer that encapsulates all the necessary boilerplate for
    server login to avoid fragile tests.<br>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com"> TB:NG
      should be pure JS, with the exception of the OS integration you
      list below. If some protocol implementation does not exist yet,
      but it's possible, e.g. LDAP, we'll write it.<br>
      <br>
      For those things that absolutely do need native calls, because of
      e.g. Kerberos credentials, we might still not come to the IPC
      question at all, because there's already a JS wrapper on npm, e.g.
      <a class="moz-txt-link-freetext"
        href="https://www.npmjs.com/package/kerberos"
        moz-do-not-send="true">https://www.npmjs.com/package/kerberos</a><br>
    </blockquote>
    <br>
    The thought I have for things like LDAP and GSSAPI is that there is
    very little value supporting those on mobile, so if I can't get them
    from an assumed-OS-installed library (e.g. OpenLDAP/WinLDAP), there
    is little point in maintaining an implementation ourselves.<br>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com"> <br>
      Let's cross that bridge when we get there.<br>
      <br>
      <blockquote
        cite="mid:5a31e3ae-e621-94df-5253-30d986ac674c@gmail.com"
        type="cite">
        <ul>
          <li>Filesystem</li>
          <li>Sockets<br>
          </li>
          <li>DNS<br>
          </li>
        </ul>
      </blockquote>
      <br>
      This is all integral part of the node.js/npm platform, e.g.
      require("fs").<br>
      <br>
      Remember that if we use existing npm libraries, they will already
      presume certain npm dependencies. E.g. if we use emailjs.js IMAP
      implementation, it already uses a certain socket module, likely
      the native node.js one. We should look out that they are somewhat
      consistent (not 13 different socket implementations by various
      libraries), but I don't see a point in rewriting library code to
      use our artificial wrapper.<br>
      <br>
      Essentially, there are already so many JS libraries on npm, and
      they give so much value, that at this point, I'd make npm support
      a requirement for any platform that we'll use. Including the
      platform APIs they use, e.g. node.js require("fs") and sockets
      etc. That's basically a requirement for all the already existing
      code.<br>
      <br>
      So, it's hard to make such decisions in isolation. We should first
      get our feet wet and make a prototype, and gain some experience
      with the new situation, and then we can derive coding standards
      and platform APIs from there.<br>
      <br>
      Essentially, I don't want to re-do NSPR in JS. That was probably
      Mozilla's biggest mistake, to write their own custom platform
      abstraction. It was a necessity back then, and maybe there was
      nothing better, but it led to the arcane platform it is today.
      Let's try to stay in sync with the existing JS community, and use
      the same platform APIs. That gives basis for collaboration, in
      both directions.<br>
    </blockquote>
    <br>
    There is striking divergence between different platforms on
    important APIs (like sockets). Sometimes, it's not possible to
    emulate APIs on all platforms (e.g., node's fs library has sync
    operations, and synchronous loads can't be emulated on some
    platforms). There is also the fact that some APIs bake in older,
    stupider API paradigms (once again, node's function (err, result)
    callback API instead of modern Promises, which is just begging to
    swallow errors). I don't think there is a single "existing JS
    community"; the platforms are just too different.<br>
    <blockquote type="cite"
      cite="mid:63e1bef2-43c7-eff2-7b74-368d8f34a661@beonex.com"> <br>
      <blockquote
        cite="mid:5a31e3ae-e621-94df-5253-30d986ac674c@gmail.com"
        type="cite">
        <ul>
          <li>Database (I think we need ACID-compliant database, and I
            don't think we want to roll our own here. Note too that
            "load it all into memory" is not going to satisfy
            performance requirements when dealing with large folders).<br>
          </li>
        </ul>
      </blockquote>
      <br>
      Again, let's cross that bridge when we get there. For starters, I
      just need preferences, mbox, and JSON. That gets me most of my
      way.<br>
    </blockquote>
    <br>
    Already in Thunderbird, we're well aware that a database API can be
    difficult or impossible to change if you get it wrong. And there's
    already one respect in which we know it's wrong--it takes too long
    to open a database. One of the things I keep harping on about is the
    need to set a goal for what a reasonable large-scale program should
    look like, and I do that because you need to look at what it's going
    to imply for your situation to design the APIs appropriately.<br>
    <br>
    What I am highly concerned about in your statement is that you're
    blithely assuming that something simple is going to scale up to the
    end goals you want to scale it up to, and you're going to bake that
    design into your API, and you're going to be faced with a years-long
    refactoring attempt to try to fix that bad design (JS is naturally
    harder to refactor than C++). My simple calculations suggest that
    you're looking at a few hundred MB of data (assuming no string
    interning, and not including indexes) in a large folder (I'm using
    1M as my design criterion), and the read speeds on disks can't load
    that into memory fast enough. This means you can't assume your
    folder is going to be in-memory (we already know that from today's
    Mork database), which means every database API has to be assumed to
    be asynchronous, which has very important ramifications for the
    entire rest of the codebase. And any time you need something more
    complex than read/writeFileAtomic, well, you're probably going to
    want someone else to write that database for you.<br>
    <pre class="moz-signature" cols="72">-- 
Joshua Cranmer
Thunderbird and DXR developer
Source code archæologist</pre>
  </body>
</html>