JIRA UI in TCL

Problem statement (rant)

I don’t like JIRA’s web-UI. It’s a gigantic program that takes up an unnecessary amount of time to load and function. The initial page-load is slow. Subsequent page loads (as I navigate through the program) are slow. And all of this to serve up a glorified to-do list. It’s rude of the developers to require users to consume so much processing power for a todo list.

It’s not just the browsers that have to do so much work; it gets worse. The official Android client to JIRA weighs in at a ~26MB download. 26MB! That’s just rude.

For comparison, the Ubuntu packages for the GNU C Compiler and the Standard C library weigh in at a combined ~43 MB. Why does a project-management (fancy-pants word for todo-list managment) program weigh over half of of this?

The web-UI is lighter than the Android client, but not by much. I did a full-refresh of a page that shows one issue. By the time the UI got around to displaying the comments, about 100 HTTP requests were made by the browser, and ~18MB (18874368 bytes) of data was downloaded. That’s rude.

For a subsequent page-load of a linked issue, the browser made ~50 HTTP requests and downloaded ~60kB (61440 bytes) of data before it displayed comments. At this rate, I’d have to browse over (18874368 / 61440 =) 307 different issues just to breakeven for the initial JS load.

I don’t know what the JIRA product designers do, but I don’t think they’ve figured out how people use browsers. Specifically, that people use tabbed-browsing nowadays. Every programmer and PM and designer I know has at least 20 browser-tabs open. They don’t have only 1 JIRA tab open. And sometimes they click a link to open in another tab. I opened a linked issue in a new tab which downloaded 5MB in ~50 HTTP requests before the Javascript displayed comments. Ridiculous.

This is so wasteful, and it doesn’t need to be. My workflow (YMMV) for JIRA involves performing a search (~500kB) or looking at the view of the current sprint, then loading upto 5 tickets (most likely related to each other) (each ~70kB) in their own tab, and then reading the comments (included in the issue JSON payload already) and perhaps adding my own (less than 1kB), and changing the status of the tickets (less than 200 B). That’s a grand total of less than 900 kB of data. That’ll be my typical day; the rest of the time I’m programming. Even if we increase this estimate by 10x, that still comes to less than 10 MB of data transfer to and from JIRA.

My beef with JIRA is with their web-UI, not their API. Thanks to their API, I can just make my own interface to the JIRA; one that satisfies my use-case while not abusing my computer.

Options

Intermediate application server

This solution involves writing a stateless application server that makes API calls to JIRA and converts the response to HTML and serves up the HTML to a client. Easy-peasy. If I want some pretty added to this, I can sprinkle in some CSS.

This can be done very easily in Ruby on Rails, Ruby’s ‘Sinatra, NodeJS’ Express, or Python’s Flask frameworks.

TUI

I’m just dealing with a todo-list. I don’t need a GUI for this. This solution involves writing a stateful program that runs in a terminal emulator and serves a navigable interface to a user. Add some Ncurses and enjoy your RAM.

CLI

I’m just dealing with a todo-list. Do I really need a “menu system” for this? I don’t think so. How about I just make a stateful program that I can interact with through a REPL? Fancy-pants statistical programs like R and Stata work fine through a REPL. Forth and LISP and Ruby and Python and clients for PostgreSQL and MySQL work fine through a REPL. A todo-list should be fine through a REPL.

The best part about a REPL is that the program interacts with the standard streams; stdin, stdout, & stderr. It’s a simple printing system for output, not a complex painting system that a TUI would require, or an eventual-painting system that a HTML-output system would require. Sticking to standard streams will force me to stick to the fundamentals of the user-experience and not tempt me into random pretty-work.

Decision

It doesn’t mean there is no temptation, though. Since I (1) got laid off due to COVID-19 and (2) am interested in fiddling with other programming languages (I’ve been working with Ruby for over 7 years now), I have the time to really commit to making this in other programming languages. I’m able to afford the luxury of considering more than just pure programmer productivity, and I’m going to use that luxury.

While reading up on Forth, I found out about Tcl. This programming language was created as a C library and intended to augment C programs. That sounds great. It’s the path that Clojure followed; the Clojure language is implemented as a Java library. This allows Tcl programs to call C functions and libraries very easily. As much as I like the idea of Forth, I like the idea of reusing other people’s work even more, and there is a huge body of code available in C.

Results

I’ve made a TCL program that does

  • basic text-search for issues in JIRA
  • allows the user to “go” to an issue
  • print out the description
  • print out the summary
  • print out the comments
  • add a comment
  • assign the issue to myself (my user)
  • unassign the issue

This is all done in 110 lines of TCL code.

The program has 2 external dependencies: cURL and JQ. I wanted to make this program using as few dependencies as possible. I looked only at the manpages of the base language and didn’t want to figure out how to make HTTP calls in TCL myself. Same with JQ. For the last 1-2 features I pulled in the “::json” & “::json::write” procedures from the standard library.

I think Tcl is a fine enough language, and have only syntactic issues with it. I think its semantics are quite straightforward. I suppose that is par for the course nowadays; I find that all the dynamically typed “scripting” languages have the same semantics. The flow of a TCL program doesn’t feel all that different from a Ruby or Python or Nodejs program. It’s all the same nowadays; these languages have essentially converged.

And that’s how I have a completely usable (I actually used it over my last 2 weeks at work) program that allows me to perform 80% of my JIRA tasks using a miniscule amount of CPU and RAM. The time utility, when used with the “-v” option, shows this program using a maximum of 12MB of RAM even when it is used to traverse over multiple issues. I expect the total usage is around 30MB of RAM, once you include the cost of using curl and jq. I also expect the RAM usage to go down were I to switch JSON-parsing from jq to the Tcl standard-library.

This program took ~30 hours to get to this stage. This includes learning the language and its idioms, and learning the relevant parts of the JIRA API. Building the program was very simple, one step at a time.

Another point is that I’m not using curl correctly. I’m shelling out to a new instance of curl with every call. AFAIK, the correct thing to do is to use a binding to libcurl, for better integration. At least, that would be the case, if that package wasn’t listed as “Missing in action”. TCL has libraries that provide a lot of functionality, but one has to be careful with this. It’s not a promising sign when something as fundamental as the TLS extension to the SSL library hasn’t had an update since 2015.

Now, TCL is still in active development, and there is at least one company, FlightAware, that uses it heavily. So heavily they had multiple lectures in the last 2-3 TCL conferences about what they do with TCL. It’s very cool that they track all this live flight data from all over the world using TCL. I think I can be sure they keep their dependencies up-to-date. At least, I’d hope so.

A few fun things about TCL

Channels

One thing I noticed when browsing through the TCL manpages was “chan“. If I’m reading this correctly, then this part of the language works similarly to Golang’s channels. It allows for different functions in TCL to communicate with each other using channels. When combined with Tcl’s event-driven runtime (The same type that nodeJS brought to the masses), channels are a nice concurrency tool.

I’ve programmed with Golang channels, and found them quite enjoyable and easy to understand. I like that this is in TCL (TCL did it earlier, of course).

No types

TCL is an untyped language, just like Forth. From the programmer’s perspective, everything is a string. When you want to do something particular like add numbers, you just have to make sure you send in strings that can be converted to numbers. It’s an untyped language, and it’s on the programmer to pass the correct arguments or risk a runtime error. This puts Tcl in the same class as Forth or Assembly.

One of the consequences of “Everything is a string” is that TCL can be as extensible as LISP, since the code is a string that manipulates other strings.

It’s almost like someone took Doug McIlroy’s quote “Write programs to handle text streams, because that is a universal interface.” and made a programming language out of it.

Leave a Reply