indexpost archiveatom feed syndication feed icon

Test Driving Groff

2022-08-07

In a funny bit of coincidence I read a few different pages discussing Groff in the last week or two. While my previous experience has been limited to coercing man pages into shape I thought I might take the time to dig a little deeper and see how it compares to LaTeX (or what little LaTeX I have used).

Typesetting Briefly

Both LaTeX and Groff belong to a family of programs for typesetting documents, usually for documents like reports and books; they seem analogous to HTML. The written documents include formatting directives for laying out pages in a way that WYSIWYG editors do not.

LaTeX

Somewhat depressingly, my most-read document prepared in LaTeX is undoubtedly my resume. Keeping it up to date has been a bit of a pain because I don't really know much about the templates (styles?) that I use. Using premade styles probably impedes my actually learning much because it isn't clear where TeX ends LaTeX begins and the macros specific to the style in use extends things. Because the resume class/template/style that I am using is intended to be broadly reusable it contains a huge amount of stuff. It is about 800 lines long and I couldn't really tell you what is in it or even how to use it. If memory serves me, I think I cribbed from an example distributed with miktex and kept tweaking until I felt things were good enough.

Groff

Perhaps unsurprisingly, Groff seems to have similar issues. Typical use seems to require macro packages, either ms, mm, or mom. To be totally honest, the macros that are distributed with these packages are pretty daunting if you come to them cold. As an example, this is the macro definition for a bulleted list:

.de @IP
.if \\n[.$]>1 .nr \\n[.ev]:ai (n;\\$2)
.par*start \\n[\\n[.ev]:ai] 0
.if !'\\$1'' \{\
.	\" Divert the label so as to freeze any spaces.
.	di par*label
.	par*push-tag-env
\&\\$1
.	par*pop-tag-env
.	di
.	chop par*label
.	ti -\\n[\\n[.ev]:ai]u
.	ie \\n[dl]+1n<=\\n[\\n[.ev]:ai] \{\
.		DEVTAG-COL 1
\\*[par*label]\h'|\\n[\\n[.ev]:ai]u'\c
.		DEVTAG-COL 2
.       \}
.	el \{\
.		DEVTAG-COL 1
\\*[par*label]
.		DEVTAG-COL-NEXT 2
.		br
.	\}
.	rm par*label
.\}
..

I think these standard Groff macros carry the same burden of having to be both portable and widley reusable that LaTeX styles do. I have found the documentation for Groff better though when using a standard macro package like ms (available via man 7 groff_ms).

More importantly to me though was how easy I found it to write my own macros after doing the drudge work of laying out a page in a way that I liked. I just identified bits of repetition and then copy-pasted in my own macro definition to substitute. I won't claim to be a good Groff macro author but I think it doesn't matter so much in this context. Someone could conceivably duplicate my setup by copy-pasting the macros but why would they bother? Writing Groff like this seems like an appropriate instance of specialization that I'm happy to maintain myself. For instance, "building" the document is handled by a Makefile:

resume.ps: resume.ms resume.tmac
	groff -rHY=0 -k -ms resume.ms > resume.ps

resume.pdf: resume.ps
	ps2pdf resume.ps resume.pdf

.PHONY: clean
clean:
	rm *.pdf *.ps

For my resume the body of the Groff document ends up looking like this:

.so resume.tmac
.nameinfo "Nolan Prescott" "nprescott.com  \(en  mail@nprescott.com"

.B "Experience"
.sp -1
.job \
"Senior Software Engineer" \
"HackEDU" \
"Dec. 2021 - Present" \
"Best in class interactive cybersecurity training to companies ranging from startups to the Fortune 5"
.bullet "Customer-facing platform of development sandboxes built on Kubernetes using Python, Go, and AWS"

.job \
"Software Engineer" \
"Nuix" \
"Jul. 2020 - Dec. 2021" \
"Innovative electronic discovery software that empowers organizations to quickly find the truth from any data"
.bullet "Large-scale data ingestion for electronic discovery and information retrieval using C# and T-SQL"
.bullet "Parsing, normalization, and analysis of a wide variety of digital formats for investigation by legal professionals"

.job \
"Software Engineer" \
"RoBotany" \
"Sep. 2019 - Mar. 2020" \
"A modern agriculture company leveraging automation and software analytics to improve efficiency and crop output"
.bullet "Built software controls for the hardware systems in the company's first production-scale facility"
.bullet "Integrated Modbus controls alongside a stream-oriented industrial internet of things architecture using TypeScript, NodeJS, and Redis"

.job \
"Software Engineer" \
"Seegrid" \
"Oct. 2016 - Sep. 2019" \
"Vision-guided, autonomous vehicles for materials handling in manufacturing and distribution facilities around the world"
.bullet "Development of an inference engine to enable building customized applications through business-centric rule definitions"
.bullet "Autonomous robot fleet coordination, including traffic management and task delegation"

.job \
"Engineer" \
"PROS Inc." \
"Feb. 2013 - Aug. 2015" \
"A revenue management and price optimization company developing innovative pricing science and data analytics"
.bullet "Developed a predictive analytics service to identify sales opportunities using machine learning"

.B "Education"
.sp -1
.nudge
Bachelor of Science, Texas Tech University
.br
Lubbock, Texas

In the above the .nameinfo, .job, .bullet, and .nudge macros were all written by me. I find it satisfying that the bulk of the document is concerned with the content rather than the layout. There are a few oddities, like the spacing around the "Education" and "Experience" labels. I have not worked out the optimum way of creating the sort of layout I like, which is a bit like a two-column layout but with uneven widths and varying amounts of text. I found judicious use of indents worked just fine and while authoring the document it mostly doesn't matter because the inner working gets wrapped up in the .job and .bullet macros.

Here are the macro definitions I ended up writing:

.de nudge
.in 1.25i
..
.de bullet
.RS
.RS
.RS
.RS
.IP \(bu 2
.sp -1
\\$1
.sp -5p
.RE
.RE
.RE
.RE
.LP
..
.de rdate
.rj
.sp -1
\\$1
.sp 0.5
..
.de job
.nudge
.B "\\$1"\c
, \\$2
.rdate "\\$3"
.sp 0.5m
\\$4
.sp 0.25m
..
.de nameinfo
.ps 24
.ce 3
\\$1
.sp -8p
.ps
.sp 0.75m
\D'l 6i 0 '
.sp 1.5m
\\$2
.sp 1m
..

Results

I am pleasantly surprised to find I was able to recreate my LaTeX resume in Groff with a minimum of work. The LaTex version is seen here on the left, the new Groff version on the right:

Based on how quickly I was able to put together something based only on a reference document and the manual I can see reaching for Groff in the future if I find myself writing a more formal document than something like HTML will allow. This is a nice change of pace compared to LaTeX, where I own Lamport's LaTeX, A Document Preparation System and still don't really feel like I understand it. I feel pretty confident that I can take my 45 lines of macros and get back up to speed on any system that supports the ms macro package (which I think dates back to the 1970s). Changes are easy and there is very little to understand deeply. I like it!

One More Goofy Consequence of Groff

As far as I know, Groff supports more output targets than LaTeX so something like this is reasonably easy to achieve:


	       ───────────────────────Nolan─Prescott────────────────────────

			   nprescott.com  –  mail@nprescott.com


Experience  Senior Software Engineer, HackEDU			       Dec. 2021 ‐ Present
	    Best  in  class  interactive  cybersecurity training to companies ranging from
	    startups to the Fortune 5

		    • Customer‐facing  platform	 of   development   sandboxes	built	on
		      Kubernetes using Python, Go, and AWS


	    Software Engineer, Nuix				     Jul. 2020 ‐ Dec. 2021
	    Innovative	electronic  discovery  software	 that  empowers	 organizations	to
	    quickly find the truth from any data

		    • Large‐scale data ingestion for electronic discovery and  information
		      retrieval using C# and T‐SQL

		    • Parsing,	normalization,	and  analysis of a wide variety of digital
		      formats for investigation by legal professionals


	    Software Engineer, RoBotany				     Sep. 2019 ‐ Mar. 2020
	    A modern agriculture company leveraging automation and software  analytics	to
	    improve efficiency and crop output

		    • Built  software  controls	 for the hardware systems in the company’s
		      first production‐scale facility

		    • Integrated Modbus controls alongside  a  stream‐oriented	industrial
		      internet of things architecture using TypeScript, NodeJS, and Redis


	    Software Engineer, Seegrid				     Oct. 2016 ‐ Sep. 2019
	    Vision‐guided, autonomous vehicles for materials handling in manufacturing and
	    distribution facilities around the world

		    • Development of an inference engine  to  enable  building	customized
		      applications through business‐centric rule definitions

		    • Autonomous  robot	 fleet	coordination, including traffic management
		      and task delegation


	    Engineer, PROS Inc.					     Feb. 2013 ‐ Aug. 2015
	    A revenue management and  price  optimization  company  developing	innovative
	    pricing science and data analytics

		    • Developed	  a   predictive   analytics  service  to  identify  sales
		      opportunities using machine learning


Education   Bachelor of Science, Texas Tech University
	    Lubbock, Texas

Notes to Self

I'm sure I'll forget these unless I make a note: