6

How to apply refactoring on Latex code?

Questions here on refactoring most frequently state, the OP did or wanted to do some refactoring on Latex code, but struggled with some technicality. Though the specific struggle was solved via this community, the process of applying refactoring hardly ever is shown.

What should I do to refactor any Latex code, e.g. as in this example?

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}

\begin{document}
 Some text with duplicates: The fox jumped over the ditch. The dietch was no dutch.
 
  \begin{tikzpicture}
    \node[anchor=west,red]      (A) at (0,0)    {hello wrold};
    \node[anchor=west,orange]   (B) at (0,-1)   {it's a beautiful world};
    \node[anchor=west]              at (A.east) {here we go};
  \end{tikzpicture}
\end{document}

result

2
  • 3
    Studies have shown that programmers can optimize for one objective easily, a second objective with a lower prioity, and possbily a third with an even lower priority. If you make all objectives a priority, you will get code that does nothing well. Commented Aug 25, 2024 at 17:15
  • @JohnKormylo, thank you for sharing. // In contrast, refactoring is a one-problem-at-a-time approach. Commented Aug 25, 2024 at 17:20

2 Answers 2

8

General remarks

My focus here is on the process of refactoring in a Latex context.

Code refactoring is a broad topic with the objective to restructure existing code without changing its functionality (English Wikipedia). As a result code becomes easier to read, to understand and to maintain. The German version on refactoring (German Wikipedia) mentions possible objectives of refactoring activities:

  • (R) making code easier to read
  • (U) or easier to understand
  • (X) or easier to extend
  • (S) or avoiding code redundancy (simplification)
  • (T) or improving code testability

In coding, e.g. in Latex, looking for opportunities to refactor should become second nature. I.e. do it often, perhaps even continuously.

Levels of refactoring

Most Latex users just create content, like text or graphics, using standard language features and packages, and do some tweaks on layout or visual appearance. For these I find generalization and clean-up the most effecitve refactoring strategy (see my example below).

Power users, e.g. when developing packages or document classes , may be also concerned, and perhaps even more, with data structures and data processing. For these I suggest to walk trough Martin Fowlers online catalogue of refactoring and translate the suggestions into their toolset wrt. Latex.

Note: Martin Fowler lives in the world of Objects, UML and Systems. So his catalogue may be hard to translate for those who just write content. But it's worth a try or two.

Whatever you do, apply knowledge you already have or gained e.g. via questions and answers on this site.

The process of refactoring ...

... is simple, while keeping aboves objectives in mind:

  • write something
  • spot refactoring opportunities (or necessities)
  • refactor, decide and verify/test
  • repeat

This is easy to do when working on your own code files, and a bit harder (i.e. lengthier) to do when documenting as an answer.

Refactoring the code example using generalization and clean-up

Using some code more than once, including errors or similarities or variations, is an opportunity to refactor by generalization.

The text

Obviously we have some redundancy or duplicates here wrt. the "ditch":

 Some text with duplicates: The fox jumped over the ditch. The dietch was no dutch.

So, replacing a written "dietch", a typo, by a standard would be more useful ... especially when the whole document will talk about ditches in all shapes and forms. So, why not introducing a macro \dtch?

\newcommand\dtch[0]{ditch}
...
 Some text with duplicates: The fox jumped over the \dtch{}. The \dtch{} was no dutch.

At least this improves reading (R), gives less redundancy (S) and can be extended easily later (X), once you discover, you want all ditches in bold: Change in one place only.

The Tikz code

What kind of things are repetitive or similar here?

 \begin{tikzpicture}
    \node[anchor=west,red]      (A) at (0,0)    {hello wrold};
    \node[anchor=west,orange]   (B) at (0,-1)   {it's a beautiful world};
    \node[anchor=west]              at (A.east) {here we go};
 \end{tikzpicture}

Same:

  • the anchors
  • "world", again with a typo

Similar:

  • color
  • nodes name
  • y-coordinate

So an obvious refactoring step would be to replace all those anchors by one style:

 % ~~~ style refactored ~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \node[aw,red]       (A) at (0, 0)   {hello \wrld{}};
    \node[aw,orange]    (B) at (0,-1)   {it's a beautiful \wrld{}};
    \node[aw]               at (A.east) {here we go};
 \end{tikzpicture}

Where to go from here?

Option 1: The first two node-lines look very similar and it's tempting to replace those more than one line by a loop, like so:

\newcommand\wrld[0]{world}
...
 % ~~~ option 1: loop ~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \foreach \col/\nm/\y/\t in {red/A/0/{hello \wrld{}},
                                orange/B/-1/{it's a beautiful \wrld{}}}
        \node[aw,\col]  (\nm) at (0,\y) {\t};
        
    \node[aw]               at (A.east) {here we go};
 \end{tikzpicture}

Now, changes just are confined to the list of data tupels. Depending on your preferences you may find this a good or bad result wrt. aboves objectives. This happens frequently, so you may want to investigate alternatives.

Option 2: Why not absorbing the two node statements by macro named \nd? This way you preserve the codes structure (2 lines of nodes) while absorbing all its changes as parameters to pass:

\newcommand\wrld[0]{world}
\newcommand\nd[4]{\node[aw,#1] (#2) at (0,#3) {#4};}% 1:col, 2:nm, 3:y, 4: txt
...
 % ~~~ option 2: macro ~~~~~~~~~~~~~~~~~~~~ 
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \nd{red}   {A}{ 0}{hello \wrld{}}
    \nd{orange}{B}{-1}{it's a beautiful \wrld{}}
    
    \node[aw] at (A.east) {here we go};
 \end{tikzpicture}

Testing and deciding

Here we test just by compile and looking at the visual outcome. Now, all 3 options for Tikz refactoring give the same result:

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}

% ~~~ macros ~~~~~~~~~~~~
\newcommand\dtch[0]{ditch}
\newcommand\wrld[0]{world}
\newcommand\nd[4]{\node[aw,#1] (#2) at (0,#3) {#4};}% 1:col, 2:nm, 3:y, 4: txt

% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{document}
 Some text with duplicates: The fox jumped over the \dtch{}. The \dtch{} was no dutch.
 
 % ~~~ style refactored ~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \node[aw,red]       (A) at (0, 0)   {hello \wrld{}};
    \node[aw,orange]    (B) at (0,-1)   {it's a beautiful \wrld{}};
    \node[aw]               at (A.east) {here we go};
 \end{tikzpicture}
  
  
 % ~~~ option 1: loop ~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \foreach \col/\nm/\y/\t in {red/A/0/{hello \wrld{}},
                                orange/B/-1/{it's a beautiful \wrld{}}}
        \node[aw,\col]  (\nm) at (0,\y) {\t};
        
    \node[aw]               at (A.east) {here we go};
 \end{tikzpicture}


 % ~~~ option 2: macro ~~~~~~~~~~~~~~~~~~~~ 
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \nd{red}   {A}{ 0}{hello \wrld{}}
    \nd{orange}{B}{-1}{it's a beautiful \wrld{}}
    
    \node[aw] at (A.east) {here we go};
 \end{tikzpicture}
  
\end{document}

options

For my taste for the time being I'd stay with the style refactored.

Clean-up ... Result

Removing all obsolete code will give the (intermediate) result:

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}

% ~~~ macros ~~~~~~~~~~~~
\newcommand\dtch[0]{ditch}
\newcommand\wrld[0]{world}

% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{document}
 Some text with duplicates: The fox jumped over the \dtch{}. The \dtch{} was no dutch.
 
 % ~~~ style refactored ~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}[
    aw/.style={anchor=west},
  ]
    \node[aw,red]       (A) at (0, 0)   {hello \wrld{}};
    \node[aw,orange]    (B) at (0,-1)   {it's a beautiful \wrld{}};
    \node[aw]               at (A.east) {here we go};
 \end{tikzpicture}
   
\end{document}

It's less visible here in this simple example: if you add more code (i.e. functionality) and refactor in parallel, code tends to become:

  • more compact
  • more versatile
  • less prone to errors
  • less noisy
  • somehow more beautiful

Recap: your major tools

Unless you are a La/Tex guru with more ressources to unlock you may want to use at least these tools frequently when refactoring Latex code:

  • telling comments
  • indenting (see structured programming)
  • \newcommand (and also \newenvironment, \renew... etc.)
  • file backups or versions (perhaps even git etc.)
  • features from Latex and/or packages (like Tikz)

Some of my own examples

Over time I refacted code from questions. Often I documented the process, sometimes only the steps taken.

Process in detail on subject:

Documented refactoring steps taken on package:

7
  • 1
    I've only skimmed this, but looks very useful - thank you! but you started with ditch and dietch and ended up with only ditches. are we supposed to assume the other is a typo? Commented Aug 25, 2024 at 17:59
  • Thank you. // Yes. Thought this was obvious enough. Commented Aug 25, 2024 at 18:06
  • 2
    not to me. assuming the words are all supposed to be english, it's obvious the second sentence has errors, but it isn't obvious what it is supposed to be. it isn't as if 'The ditch was no dutch.' makes sense. (certainly not obvious sense.) Commented Aug 25, 2024 at 21:11
  • 4
    I'm not convinced by the actual example, but I appreciate the conceptual explanations. I would generally try to use more semantic markup than aw which gets confusing if you later decide you want the anchors to be south east, say. and ``world` is much more readable and less cluttered than \wrld{}. Commented Aug 25, 2024 at 21:24
  • 1
    hmm ... 'refactoring', 'prototype'. demystifying terms is turning out to be strangely disappointing ;). Commented Aug 28, 2024 at 1:33
5

I think it is easiest to show by example.

I think of my answers on this site the one that most clearly shows refactoring is

Taking Alain's code https://tex.stackexchange.com/a/39211/1090

and refactoring it to produce the same output but code formatted as

https://tex.stackexchange.com/a/79151/1090

As I commented there

The output is nice, but the input didn't look very christmasy so I optimised it a bit in an answer below.

2
  • Thank you. // Do I overlook a procedural answer to "how to refactor Latex?". // The second one is what people feared Perl-code would look like ... ;-) Commented Aug 27, 2024 at 8:38
  • 1
    why am I so sure where this points without even looking? Commented Aug 28, 2024 at 1:31

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.