• 2015 Review

    Professionally, I grew a lot in 2015. I started working at RJMetrics in April 2014. It was my first experience at a start-up, and my first real foray into writing software for the web. The shift in workplace culture and technology I experienced that first year made me excited and anxious. I was learning new stuff at a fast clip, and I'm happy to say that in 2015 that rate of learning didn't slow down.

    In 2015 I made the jump from mostly front-end development to a mixture of front- and back-end. I finally started learning Clojure and functional programming.

    I still do front-end work, and I've become someone that other members of the team come to with AngularJS questions. I feel more comfortable with Sass and styling than I did at first, and I'm more familiar with Gulp and our other front-end tooling. I'm looking forward to playing with Angular2, and maybe even ClojureScript and/or React down the line.

    Over a few weeks in my downtime I built a single page app using Angular. Tumblr Top gives users a quick visual overview of a Tumblr blog's top original content.

     

    Screen Shot 2016-01-06 at 8.34.52 PM

      

    Screen Shot 2016-01-06 at 8.35.37 PM

     

    This was fun because it was my first Angular app from scratch, my first experience with Material Design, and the first project I put on my public GitHub account.

    It took me a while to pick up Clojure. I'd only ever done imperative programming, and I initially found Lisp syntax intimidating and confusing. And there was so much vocabulary. Arity, records, multimethods, monads, macros, etc.

    There was a chicken/egg situation where I wanted to work on a Clojure project to learn the language, and I needed to learn the language to work on a Clojure project. Slowly, I began edging into it. Outside of work I did 4clojure problems, occasionally visited Clojure for the Brave and True, and began reading The Joy of Clojure (which I gave up and then later picked up again).

    I did get a chance to use Clojure heavily at work--it came near the end of the year when my team was tasked to design and implement a notification system. In short, this new service allows for end-users to receive notifications about actionable errors throughout the system. The various microservices publish some event messages about their state, and the notification service consumes those messages, sending the proper email and/or in-app notifications. Making the new service robust, scalable, extensible, and idempotent was challenging, but it was probably the most important professional experience I had in 2015. The project is nearly done, but I finally feel comfortable with Clojure. I'm excited to continue using this beautiful and expressive language.

    Over the summer I gave a presentation at work about the publish-subscribe messaging pattern. I enjoyed researching this topic and thinking about ways that our microservices could make use of an event bus and the pub/sub pattern.

    Our production infrastructure at work is largely on AWS. This year, mostly due to my role on the notification project, I got a lot of exposure to this DevOpsy side of things. The notification pub/sub system employs SNS and SQS in a fanout topology, where message producers publish to an SNS topic. That topic fans out to one or more SQS queues, which consumers then read from. I touched other parts of AWS, too--OpsWorks and CloudWatch come to mind.

    In general, I feel more comfortable at work in terms of the environment and my place within the company. I also feel more confident in my abilities.

    The coming year looks promising. I want to increase my focus on my hobbies. I want to learn more about Clojure and use it in a personal project (maybe something with machine learning?)

    PS: A few weeks ago I started using Taskwarrior to keep a todo list at the command line, and it's helped my focus at work tremendously.

    Outside of work, in 2015 I:

    • Finished reading Infinite Jest. It took me an embarrassingly long time, but it was likely the best book I ever read. In 2016 I want to read more. I renewed my library card and everything.
    • Moved the literary web magazine I help run from loose HTML/CSS to WordPress. It's now a lot better for mobile devices, and a lot easier to maintain and expand.
    • Tried out jogging...it's pretty fun. By the end of that experiment I was able to run three miles straight. Hopefully I'll have the drive to pick it up again in the spring.
    • Visited Savannah, Nashville, and North Carolina's Outer Banks. I should travel more, too.

  • deWordify Updated

    I just updated deWordify, a tool to convert Microsoft Word files to HTML. Now, you can optionally remove any unnecessary non-breaking spaces or line breaks formatted as paragraphs that are sometimes in Word files.

    I made deWordify to help me format the Microsoft Word writing submissions that end up on the online literary magazine I maintain. I like that process improvement doesn’t really feel like work, but it’s probably some of the most important work.

     


  • Machine Learning

    I started taking a Machine Learning course through Coursera. Finished the first programming assignment last night, which was to implement gradient descent for linear regression with one variable in Octave (or MATLAB). I’m not sure I’ll ever get to use ML at work, but it’s interesting as heck.


  • DataTables TableTools Extension with AngularJS/RequireJS

    We use a flexible jQuery plug-in called DataTables at my job to handle generating large display tables. One often-requested feature was the ability to download the table as a CSV file. DataTables has an extension called TableTools that I used to implement this feature. TableTools lets you copy the table to the clipboard, export to CSV, XLS, and PDF, and also gives a clean, large view suitable for printing. Getting TableTools to work w/ AngularJS was a bit challenging.

    // Define as an AMD module if possible
    if ( typeof define === 'function' && define.amd ) {
    	define( ['jquery', 'datatables'], factory );
    }
    else if ( typeof exports === 'object' ) {
        // Node/CommonJS
        factory( require('jquery'), require('datatables') );
    }
    else if ( jQuery && !jQuery.fn.dataTable.TableTools ) {
        // Otherwise simply initialise as normal, stopping multiple evaluation
        factory( jQuery, jQuery.fn.dataTable );
    }

    ^ This logic at the very end of dataTables.tableTools.js  was conflicting with RequireJS. Specifically, require.js was properly loading the DataTables file (jquery.dataTables.js), but the conditional block here was trying to load dataTables.js. A 404 error was being thrown. I only needed the very last branch of the if statement:

    factory( jQuery, jQuery.fn.dataTable);

    You can check if TableTools (or another extension) is being properly loaded by using the DataTables Debug Bookmarklet. The debug bookmarklet shows you what extensions are correctly installed: Screen Shot 2014-07-16 at 6.50.46 PMdownload it from here. Once TableTools is installed, you should be able to use it with code like this:

          # Set up the TableTools DataTables extension for CSV exporting
          _createTableTools = (myDataTable) ->
            tt = new $.fn.DataTable.TableTools( myDataTable,
              sSwfPath: "/path/to/TableTools/swf/copy_csv_xls.swf"
              aButtons: [ "csv" ]
            )
    
            $(tt.fnContainer()).insertBefore('div.dataTables_wrapper');

    That’ll place a CSV download button right above an existing DataTable. I call this function after I create a table, passing in the DataTable instance as a parameter. Note that /path/to/TableTools/swf/copy_csv_xls.swf is from the site root, not the machine’s filesystem root. Note also that div.dataTables_wrapper is created by default when the DataTable is made–you don’t have to create that element yourself. You can also create the TableTools object as a property of the DataTable. Something like this should work:

            table = elem.find('table').dataTable(
              sDom: 'T<"clear">lfrtip'
              tableTools:
                sSwfPath: '/path/to/TableTools/swf/copy_csv_xls.swf'
              # Other table properties
              # ...
            )

    Repositioning the buttons anywhere besides on the DataTable is…well…annoying. I think you have to first initialize the TableTools DOM element on the DataTable, and then remove it from its parent node and append it to another node. Even if you get the DOM element in the correct place, I found there were a few CSS gotchas. I won’t write about them here, as the changes a coworker and I made were specific to our layout. I had to change some of the default styles created within the ZeroClipboard_TableTools.Client.prototype section of dataTables.tableTools.js. If the buttons appear but aren’t working, ensure that the path to the SWF file is correct and that the actual SWF element in the DOM is in the correct space. When I moved the buttons from their default position, I found the SWF element was being absolutely positioned, which in this particular layout made it sit invisibly in the top left-hand corner of the browser window. When you’re done though, you’ll have export functionality sitting right alongside the DataTable. Screen Shot 2014-07-16 at 7.12.22 PM


  • Weird ellipsis in AngularJS&#8230;

    Today at work I came across a strange issue.

    I had written a function that would take some raw numeric data, then format it to be displayed. For instance, ‘1.234567’ might become ‘$1.23’.

    In Angular I would normally just do plain old data binding like this:

    $scope.adjustedValue = '$1.23'
    <div></div>

     

    That was working fine for most cases, but some of our values required special formatting:

    $scope.adjustedValue = '<span class="prefix">$</span>1.23'

     

    When I used ng-bind-html to let me bind a variable containing HTML, however, an ellipsis was being appended to the end of my number.

    <div ng-bind-html="adjustedValue"></div>

     

    Instead of ‘$1.23’ as I expected, I was seeing ‘$1.23…’.

    I thought there was maybe some CSS being applied that was inserting that ellipsis, but when I disabled CSS the rogue ‘…’ still appeared.

    Binding with double curly braces behaved as expected, but using ng-bind-html did not. Weird.

    According to the docs for ngBindHtml: “By default, the innerHTML-ed content will be sanitized using the $sanitize service.”

    I tried bypassing the $sanitize step to see if that would solve this ellipsis problem (I also had to inject $sce into my controller):

    $scope.adjustedValue = '<span class="prefix">$</span>1.23'
    
    $scope.bypassSanitize = ->
        $sce.trustAsHtml($scope.adjustedValue)
    <div ng-bind-html="bypassSanitize()"></div>

     

    That resolved the problem; the output no longer contained an ellipsis. Always kind of unsettling when you’re not exactly sure why something works…

    The $sanitize method will remove any unclean HTML from your bound variable, so forgo it with that caveat. Indeed, when I set $scope.adjustedValue = &lt;script type="text/javascript"&gt;alert('hello');&lt;/script&gt; it was clear that arbitrary HTML was being bound. In this particular case our backend is scrubbing the possible output values, so I was able to move ahead using this solution.