My name is Jonathan. I have 8+ years of experience working as a
technical writer in the defense industry.
I can introduce you to various software, various coding languages, and the technical writing style.
I can also help you develop portfolio items.
Here is a list of software I know:
| OxygenXML | For writing XML-based documents. |
| Microsoft Word | For writing OOXML-based documents and generating PDF files (via Adobe Acrobat integration). |
| DITA Open Toolkit | For interpreting DITA code and generating output such as Word files. Free and highly customizable. |
| MadCap Flare | For writing HTML-based documents with advanced versioning features. |
| PTC Arbortext | For interpreting XML code and generating PDF files. |
| Adobe Acrobat DC | For viewing PDFs. Also for signing and appending signature pages. |
| Snagit | For screenshotting portions of the screen and editing them. |
| Adobe Illustrator | For creating "Controls and Indicators" (or "ctrlind") images. Also for image processing. |
| Jira | For issue tracking and project management in the Internet browser. |
| SmartBear Code Collaborator | For collaborating with others to comment on a variety of file types and track fixes in the Internet browser. |
| Visual Studio Code | For writing and executing scripts of all kinds. Free and highly customizable. |
Here is a list of coding languages I know:
| XML | Extensible Markup Language (XML) code structures data inside "tags":<para>This is a paragraph.</para>XML is a catch-all term; since the language is extensible, various standards exist. |
| XSLT | Extensible Stylesheet Language Transformations (XSLT) code defines how XML code is transformed into other coding languages. |
| XSL-FO | Extensible Stylesheet Language Formatting Objects (XSL-FO) code defines how XML code is transformed into paginated content such as PDFs. |
| DITA | Darwin Information Typing Architecture (DITA) is an open XML standard for topic-based authoring. This interfaces with the DITA Open Toolkit to generate custom output of all kinds. |
| OOXML | Office Open XML (OOXML) is the XML standard used by Microsoft Word, Excel, and PowerPoint. If you change the file extension to .zip, the OOXML is immediately accessible. |
| MIL-STD-40051-2D | MIL-STD-40051-2D is the XML standard used by the U.S. military for Technical Manual Change Request (TMCR) Interactive Electronic Technical Manual (IETM) variants. Examples include the Operator User Manual (OUM) and Standard Maintenance Manual (SMM). |
| HTML | HyperText Markup Language (HTML) code defines the content and structure of web pages. |
| CSS | Cascading Style Sheets (CSS) code defines the style of web pages. |
| DTD | Document Type Definition (DTD) code defines two (2) distinct things:
|
| Batch scripting language | Windows Batch (.bat/.cmd) code directs the Windows Operating System to perform actions via the console. This is a potential part of the publishing process for DITA Open Toolkit if paid software such as OxygenXML is not used. Python is another option. |
| ANT | Apache Ant (.ant or build.xml) code is XML-based and exclusively performs "build" scripts. In other words, it performs compiling / packaging / deploying tasks. This is a potential part of the publishing process for DITA Open Toolkit if paid software such as OxygenXML is not used. Python is another option. |
The intent of this curriculum is primarily to introduce you to the technical writing style (a core skill) and how it may be wielded to create various "deliverables" common to the technical writing profession.
These "deliverables" can be a part of your portfolio.
Two (2) technical writing styles exist:
This curriculum primarily focuses on the latter: the procedural style.
The procedural style is for writing, in order, the chronological steps of a task.
When writing the procedure for a task, the most important thing is to maintain context.
To accomplish this goal, divide the steps into three (3) basic parts: prepositional phrase, command, and result.
Here is an example:
From Balloon Color drop-down, select an appropriate color. The balloon color updates to reflect the change.
The prepositional phrase tells the reader
where they need to be prior to executing the command.
This can be a digital space like "desktop" or "window" or "pane" or "dialog":
This can link more than one concept to guide the reader:
This can be a field, box, or drop-down:
When the context changes from step to step, the best way to maintain context is to include a prepositional phrase at the beginning of the step.
When the prepositional phrase comes first, it's harder to miss.
When the context does not change, the prepositional phrase can be excluded or positioned after the command to help the sentence flow more naturally.
In practice, pay special attention to when software windows close and try to include the prepositional phrase whenever the current context disappears.
The command tells the reader
what to do with a present tense verb.
If a numbered step does not contain a command, then it is not a true step and should be merged into the previous numbered step or converted into a note. If unsure, consider tacking on the command to "observe" or "ensure" or "verify".
The result tells the reader
what should happen after the command has been executed.
Endeavor to always include the result. Exceptions exist (e.g., when the command is one of several short, repetitive tasks, and nothing happens until later).
Endeavor to always use a present tense verb in the result. Exceptions exist (e.g., when the result is delayed or can only be expressed with passive language).
When the result links with the next step's prepositional phrase, it maintains the most context (e.g., [...] Balloon Cheer Coefficient dialog displays. From Balloon Cheer Coefficient dialog, [...]).
This is often more wordy than necessary and creates unwanted bloat, but it helps the reader with especially confusing or technical tasks. Use your best judgment.
Sometimes, you will encounter content that seems to blur the line between informational and procedural. If you can't translate it to be 100% procedural, that is okay.
You may even elect to not change obscure content like this and focus your attention elsewhere.
So long as you keep the technical writing style in mind, your edits will make the content
better than it was before.
A "topic" is a self-contained, modular unit of information that focuses on a single subject or task. One (1) component .xml or .dita file generally translates to one (1) topic.
There are three (3) basic layouts for a topic:
General information is written in the informational style.
Procedural steps are written in the procedural style.
There are two (2) types of topic titles:
must begin with a present tense verb.
Capitalize the first word in the title and every other word... except short articles, coordinating conjunctions, pronouns, and some short prepositions:
| Articles | a, an, the |
| Coordinating Conjunctions | and, but, or, nor, for, yet, so |
| Pronouns | their, his, her, its, who, whom, whose |
| Short Prepositions (usually 3 letters or fewer) | at, by, for, in, of, on, to |
Do capitalize these words: with, from, over, under, into, about, before, during, after, through, between, as, than, until, onto, upon, because, while.
General information, written in the informational style, has the fewest rules. Yet the intent is
always to inform, not to persuade or entertain.
General information can include:
General information cannot include instructions (because that is what procedural steps
are for).
Procedural steps, written in the procedural style, are organized neatly in an ordered (numbered) list.
Procedural steps can include:
In Microsoft Word, when the cursor is active in a numbered step, and you press [tab], an indented step appears and it adopts the next tier of numbering.
The order is like so: decimal, lower-alpha, lower-roman, (decimal), (lower-alpha), (lower-roman).
Here is an illustration of nested procedural steps:
Deeper levels of nesting indicate deeper levels of context within the task. The context can be conceptual (i.e. divide tasks into smaller tasks) or related to the digital spaces (i.e., when a window or dialog appears, the context moves "forwards", and when a window or dialog closes, the context moves "backwards").
When you arrange steps like this, which is common, the "parent" step (the one with "child" steps nested inside of it) must still contain a complete idea; do not merely write "Do the following:" but summarize, with a present tense verb, the task that is delineated below.
As previously discussed, to maintain context, divide the steps into three (3) basic
parts when considering how to write them: prepositional phrase, command, and result.
The prepositional phrase tells the reader
where they need to be prior to executing the command.
The command tells the reader
what to do with a present tense verb.
The result tells the reader
what should happen after the command has been executed.
When writing in the informational style (for general information), use
any necessary verb tenses.
When writing in the procedural style (for procedural steps), use any necessary verb tenses, but
favor the present tense (imperative mood).
A given paragraph might be about the past, or the future, or something that only happens when certain conditions are met. In cases like these, it is appropriate to use various verb tenses to communicate the information accurately.
When I say to "favor the present tense (imperative mood)", I am mostly referencing this particular circumstance:
From Balloon Color drop-down, select an appropriate color. The balloon color updates to reflect the change.
From Balloon Color drop-down, the user selects their desired color. The balloon color will update to reflect the change.
The second example is not favored for two (2) reasons:
Remember, the reader is performing the task in the present, so even the result should favor the present tense unless it is significantly delayed. When the result is significantly delayed, consider qualifying the statement: "The balloon color will update to reflect the change when the simulation is restarted."
As for topic titles, to recap, there are two (2) types of topic titles:
must begin with a present tense verb.
Consider the titles of the following examples (but you can ignore the content):
general information title > noun phrase related to the subject
From a jungian perspective, balloon color has myriad effects on conscious and unconscious parts of the mind. Therefore, it is possible to leverage potential balloon color effects against psychological phenomena. To cultivate and preserve the optimal psychological balance in human subjects exposed to a balloon, balloon technicians consider variables known as Balloon Color Contributory Factors (BCCF):
general information title > present progressive "-ing" verb phrase
BCCF represent the key variables that influence how (or whether) a balloon's color is perceived and psychologically processed by a subject. A given balloon's "archetypal impact" (the effects of universal, inherited patterns in humanity's collective unconscious) can be amplified, diminished, or entirely negated by BCCF. The intent is always to amplify the archetypal impact, never to diminish or negate, but the archetype itself may change "laterally" resulting in the axiom that a balloon's attributes inform its identity, and its identity informs its perceived archetype and archetypal impact.
procedural steps title > begins with a present tense verb
procedural steps title > present progressive "-ing" verb phrase
procedural steps title > doesn't begin with a present tense verb
Use bulleted (or "unordered") lists anytime you need to list things... that aren't procedural steps... or references to stuff already labeled with numbers.
Ensure the first word/phrase of each item is similar throughout (either all verbs of the same tense or all nouns). This is a principle called "parallel structure" or "parallelism".
Always include a period at the end of the final item.
Another way to use bulleted lists is to reformat sentences that have more than four (4) commas. The commas go near the end of each item, which can help the reader stay oriented.
Here is an example:
The Balloon Design Studio menu bar enables the user to:
This is sort of similar to using "serial semicolons". You don't want to do either of these things excessively when writing content yourself, but they are useful when editing content you received from someone else and you don't want to change a run-on sentence's meaning inadvertently by rewriting it.
Here is what that sentence looks like with serial semicolons instead of a bulleted list:
The Balloon Design Studio menu bar enables the user to start new balloon projects; save, load, and make duplicates of balloon configurations; access 17 editing windows, including those for color and pressurization; and run the Emergency Deflation Protocol (EDP).
Which way do you think looks better? It can be a matter of personal taste. Personally, I think the bulleted lists look better at the top of topics or in summaries (because it helps the reader glance over them), and serial commas look better in the middle of paragraphs about history or theory.
Inline images are small images nested inside a sentence. Usually they are pictures of software buttons or icons.
I recommend placing them inside parentheses.
In bulleted lists, do not use the inline image "as" the bullet; place it inside parentheses after the bolded term.
place the inline image inside parentheses after the bolded term
use the inline image "as" the bullet
XXX Copy - Copies balloon configuration.
XXX Paste - Pastes balloon configuration.
XXX Label - Opens Balloon Label dialog to designate a label for the balloon.
And... do not use inline images inside titles or captions!! This can mess up your table of contents!!
Notes, cautions, and warnings go above the paragraph or step they are associated with.
A note contains extra information that does not present a danger to property or people. Avoid stacking multiple notes on top of each other. It's better to have just one if you can.
A caution indicates a danger to property or indicates that something could break.
A warning indicates a danger to people. This can indeed happen in software, for example if the software activates dangerous machinery.
If you need to stack notes, cautions, and warnings, the proper order is for warnings to be at the
top, followed by cautions, followed by notes. But make sure they are all on the same page as the
start of the content they are associated with or the reader might not see.
Do not include instructions in notes, cautions, or warnings - only information. If you want to type instructions, try to make a step instead.
Add the following warning before a procedure step that involves moving a heavy item:
The XXX requires a two-person lift. Items weighing over 20.5 kilograms (45 pounds) shall be placed for two-person handling.
The caption goes above the table. Ensure the caption is on the same page as the start of the table.
Add figures (images) of entire windows, entire dialogs, or subsections that are easy enough to identify without more context. Do not add a figure of just a tiny button, for example.
The caption goes below the figure. Ensure the caption is on the same page as the figure.
If an image is predominantly white-colored around the edges, add a black outline.
Add red or yellow boxes around elements that the user will interact with. Red looks good on most pictures but sometimes yellow looks better. (You can also use pink, blue, green, etc., but try to be consistent.)
Avoid saying stuff like "[...] as shown in figure XXX below" immediately above the figure. It is not
necessary and adds complexity with references or numbers that won't match anymore if the content
is edited or reused somewhere else. Furthermore it may confuse the reader if the image or reference
doesn't load correctly. A
topic should be detailed
enough to follow without the figures, which are supplementary.
Write the instructions faithfully: if you merely write "make it look like it does on this figure" and the figure doesn't load or is hard to read because of compression, the reader can get stuck.
As for the image size, consider the image's width and ensure it doesn't exceed the available space between the left and right page margins. Word seems to do this automatically, but when it does, embedded text will shrink, so keep this in mind.
If the image has text in it, resizing the image resizes that text too. Then it won't match other images of its kind. Being attentive to font size in images is another example of the principle "parallel structure" or "parallelism".
And, this goes without saying, but any photos of hardware or facilities shouldn't have other secrets or protected information visible.
Whether you can use a
<title> depends on the circumstance.
In Word, try to keep your whole document at or under 6 levels of depth. (Use paragraph styles Header 1 thru Header 6.)
In XML coding projects, check the Document Type Definition (DTD) to see where titles are allowed. If the DTD says you can't put <title> where you need one... you can make a "fake" title with a bolded paragraph. It's also possible to make your own custom "outputclass" attribute for the XSL to interpret as something similar to a title.
| Favored | Not Favored |
| drop-down | dropdown, drop down |
| pop-up menu | popup menu, popup |
| checkbox | check box |
| radio button | radial button |
| dialog | dialogue, dialog box, dialogue box |
| field (when named), text box (when not named) | text field, text area |
| scrollbar | scroll bar, scroll-bar |
| sidebar | side bar, side-bar |
| toolbar (when horizontal) | tool bar, tool-bar |
| tool palette (when vertical) | - |
| taskbar | task bar, task-bar |
| menu bar | menubar, menu-bar |
| title bar | titlebar, title-bar |
| Favored | Not Favored |
| select (for GUI elements like buttons and drop-downs) | left-click, left click, press|click left mouse button, perform a simple mouse left-click, perform a single click of the left mouse button |
| click (for GUI elements like tiny collapse and un-collapse nodes, upper-right corner X buttons, negative space) | left-click, left click, perform a simple mouse left-click, press|click left mouse button |
| double-click | double click, press|click left mouse button twice in quick succession, perform a double click of the left mouse button |
| right-click on | right click on, press|click right mouse button, perform a single click of the right mouse button |
| enable (for the means to do something, not for permission) | allow |
| enter | type, type in |
| log in, log in to | login, login to |
| plug into | plug in to |
The term "enter" also implies the action of pressing [Enter] whenever applicable. You don't have to explicitly write it. Also use the term "enter" when the user doesn't press [Enter].
| Favored | Not Favored |
| required, as required, as needed | desired, as desired |
| left, right | left-hand, right-hand |
A standard "window" is a rectangular, OS-managed container that displays a software's graphical user interface (GUI). A software may have any number of distinct windows. Most standard windows have a title bar along the top.
A standard "title bar" is an OS-level, horizontal bar along the top of a window. In the Windows OS, it has three (3) standardized buttons: minimize, restore down/maximize, and close. These buttons are at the top right. They are for manipulating the window itself. (Closing a window typically sends a close request to the application, which may exit or remain running as a process in the background.)
A "menu bar" is a software-level, horizontal bar along the top of a window or application. It has drop-down menu options arranged from left to right. The options include things like "File", "Edit", "View", and "Help".
Sometimes, the title bar and menu bar are the same bar.
Window subdivisions include "panes" and "panels". These terms are not strictly standardized.
A "pane" divides a window into regions. It is
defined by its structural position as a subdivision of the window.
A "panel" is a generic container. It is
defined by its grouping of related UI elements.
A "sidebar" is a type of vertical pane that spans the left or right side of a window. A left sidebar is typically for navigation within the software and may include a "tree view" or "navigation tree" with collapsing nodes. A right sidebar is often more contextual. Sometimes it's a tool palette.
A dialog is a small window that exists to complete a task, then close. A standard dialog temporarily blocks interaction with its parent window, gaining an exclusive "focus" until dismissed. A standard dialog tends to have three (3) or fewer buttons. The options include things like "OK" and "Cancel".
A dialog can be used for:
In the Windows OS, the dialog's name is located in its title bar. If it has punctuation or reads like a sentence, consider referring to it with quotation marks (e.g., From "Pop Balloon?" dialog, select Yes.) Or you can simply refer to it as "dialog" since it gains exclusive focus and wouldn't be confused for anything else.
These are checkboxes. Notice you can check or uncheck any of them.
These are radio buttons. Notice you can only select one per group.
This is a field. You can enter free-form text.
This is a spinner. Use the up and down arrows to change the value within limits. Notice you cannot go under 1 or over 10 in this example.
This is a drop-down. You can select one option from a predefined set.
The button itself is called a "drop-down". There are two kinds.
If the drop-down is in a menu bar, its options are called "drop-down menu" and they either execute commands or open windows. You actually don't have to reference it directly: "From Balloon Design Studio menu bar, select Edit > Balloon Properties > Shape. Balloon Shape window displays."
If the drop-down is not in a menu bar, its options are called "drop-down list" or "the list" and they usually don't execute a command on their own. They are just for making a selection. (An exception might be for adjusting a live video feed, or something like that.)
When right-clicking produces a menu, it's a "pop-up menu". Right-click anywhere on this web page to see an example.
This is a date picker.
This is a time picker.
This is a color picker.
This is a file picker. In practice, though, I would call it the Choose File button. It opens a File Explorer window.
For procedural steps, bold the name of the thing that is interacted with in the command
and selections and text to enter.
Do not bold the type of thing it is (e.g., button, drop-down, key).
Do not bold anything in the prepositional phrase.
I underlined to help show what to bold. In real docs, don't do that.
From Color drop-down, select an appropriate color, then select OK.
From Color drop-down, [...]
From Color drop-down, [...]
From Color drop-down, [...]
From Search field, enter the tactical balloon's ID number. The map display centers on the selected tactical balloon.
After the map display updates, right-click on the selected tactical balloon and select Orders > Tactical Move. Then click a destination point on the map display. The tactical balloon moves tactically to the selected destination point.
To create a new Table of Contents (TOC):
For keyboard keys, bold the key name with brackets: press [Q], press [Enter], press [CTRL] + [ALT] + [DEL].
Not used for anything. If you choose to use it, do so sparingly and consistently across that use case.
Not used for anything except hyperlinks. If you choose to use it another way, do so sparingly and consistently across that use case.
Capitalize the name of the item, not what it is (e.g., Confirm button, Intervention drop-down, [Enter] key). It's the same as the rule for what to bold.
Don't excessively capitalize normal words just because they're "things in the software". It should really only be for names.
You can capitalize the names of roles within a software or system environment (like "Admin" or "Maintainer" or "Controller") and the names of formal stages of a process (like "Requirements Analysis phase" or "System Design phase").
When something's formal name is in all caps, consider whether you'll write it that way in the documentation. I prefer to make it match exactly.
You can add quotation marks around new words and phrases that could otherwise interrupt the flow of a sentence.
They also help to indicate the full names of things that have punctuation or read like a sentence.
From "Wow! Wow! Will you really - I mean REALLY REALLY - pop the Senior Admin CEO Golden Emperor Dynasty balloon??? Look out! Oh my God!" tab, expand the 30 layers of navigation tree nodes. Find and select the flashing "Do it" button.
That example is a bit silly, but you might be surprised what things are called.
Also bold the quotation marks themselves when the contents are.
A Controls & Indicators topic illustrates the locations of the interactive parts of
hardware or
software. These interactive parts are called "controls and indicators".
The term "controls" refers to parts the user interacts with such as buttons, levers, hatches, handles, toggles.
The term "indicators" refers to parts that provide feedback such as light-emitting diodes (LEDs) and electronic screens.
The breadth of parts depends on the use case.
For standard commercial products, you may include In/Out (I/O)
ports, screw holes, and mounting apparatuses. For hardware installed by your company's team as part
of a comprehensive system, do not include them because
the user is not intended to interact with them. So while other controls and indicators
may technically exist, consider first the intent behind your
"ctrlind" topic and what the user will need to know.
A Controls & Indicators topic contains, at a minimum, one (1) diagram and one (1) table.
For square-shaped images (including collages), labels begin at 11 o’clock and
proceed clockwise.
Notice the label numbers along the top side are flush with the dotted margin. This margin is in a layer in the Adobe Illustrator sample. It represents the origin of the red callout lines. The red callout numbers live in the space between the margin and the outer edge of the "canvas".
For images long on the X axis (especially toolbars), you can use the same angle for the labels. You may want to give the full image (its canvas) a width equal to the available space between the page margins.
(You can still use the previous layout for these too, as applicable.)
For images long on the Y axis (especially tool palettes and remote controllers), you can use the same angle for the labels.
You can draw a box around a portion of the image and label it with a single number, too. That entry would get more information in the table row. This helps to make the diagram easy to look at, particularly when you'd otherwise have arrows pointing into the center of the image.
The table has three (3) columns: label number, control/indicator name, and control/indicator description.
As with the procedural writing style, use a present tense verb whenever possible to
describe what the control or indicator does, and if something is conditional or significantly
delayed, endeavor to
quantify when it happens. However, this part of a manual isn't really supposed to have instructions
in it... just descriptions.
Table 1. Balloon Design Studio Main Window Controls and Indicators.
| # | Name | Description |
| 1 | New Balloon button | Creates an unnamed balloon entity at the simulation's origin coordinate. The default color is red. |
| 2 | Glitter checkbox | When checked, the system applies a glitter attribute to the next created balloon entity. This makes it visible to tactical balloons. |
| 3 | Balloon Attribute button | Opens Balloon Attribute window for designating the RGB value, alpha value, and VIP status of the selected balloon entity. |
| 4 | Video Panel | Displays video feed of balloon simulation. |
Notice the last item here is called "Video Panel" and is capitalized despite being normal words. Like I said earlier, "Don't excessively capitalize normal words just because they're 'things in the software'. It should really only be for names." But sometimes there simply isn't a name. When that happens, I prefer to capitalize it in lists ("Video Panel" for parallelism) but not in paragraphs ("video panel" for grammar).
Figure 1. Balloon Attribute Window - Toolbar Controls and Indicators.
Table 1. Balloon Attribute Window - Toolbar Controls and Indicators.
| # | Name | Description |
| 1 | New Profile button | Creates a blank balloon attribute profile. If the editor contains unsaved work, a "Save profile?" dialog displays. |
| 2 | Load Profile button | Opens a file explorer window for loading a previously saved balloon attribute profile. If the editor contains unsaved work, a "Save profile?" dialog displays. |
| 3 | Save Profile button | Saves current balloon attribute profile. If it hasn't been saved before, a file explorer window displays for naming the file. |
| 4 | RGB button | Designates color of balloon via color picker dialog. |
| 5 | Alpha slider | Designates alpha value (transparency) of balloon. |
| 6 | VIP checkbox | When checked, designates balloon as an essential unit in the simulation. When a VIP balloon is detected by an opposing tactical balloon, a flashing warning will appear in the status bar. |
Test procedures are for testing newly developed hardware, software, or systems to establish whether the product meets all of its requirements. Sometimes, the customer does it. Sometimes, your team's test lead does it while the customer observes.
When you use the technical writing style to full effect,
the text content of test procedures is extremely similar to procedural steps.
A test procedure table has, at a minimum, four (4) columns: step number, step, expected result, and pass/fail.
If you include images, consider using a landscape page and standardize the image widths. Test procedures are largely disposable in nature, so you may not want to dedicate too much time to images. But this can be a matter of your personal style too.
We won't be getting into this next detail, but there may be another column for requirement codes that link to other documentation such as the System|Software Requirements Specification (SRS), System/Subsystem Specification (SSS), and Requirements Traceability Matrix (RTM). When a step passes, it proves compliance with whatever requirements are listed in that column. There may also be a column for writing comments.
As previously discussed, to maintain context, divide the steps into three (3) basic
parts when considering how to write them: prepositional phrase, command, and result.
The prepositional phrase tells the reader
where they need to be prior to executing the command.
The command tells the reader
what to do with a present tense verb.
The result tells the reader
what should happen after the command has been executed.
| # | Step | Expected Result | Pass/Fail |
| 1 | From desktop, double-click Balloon Design Studio icon. | Login screen displays. | |
| 2 | Enter username and password, then select Login. | Balloon Design Studio window displays. |
Remove and Replace (or Remove and Install) topics describe how to safely remove hardware and replace it with new hardware. They are often grouped together in a manual's maintenance chapter.
Since these procedures may involve heavy objects, ladders, things mounted in tall racks or on the ceiling, and high-voltage electronics, "remrep" topics tend to have the most warnings.
The top of the topic lists prerequisite or initial|equipment conditions (like turning power off), personnel required (like "Operator" or "Maintainer"), and tools required (like various ladders and screwdrivers).
The body of the topic contains two (2) procedures: one for "remove" and one for "replace" (or "install").
In practice, the procedural steps can often be close to a mirror image of each other.
In the example below, notice the first step of "remove" aligns with last step of "replace". I'll use color and underlines to help illustrate the reverse order. Terms are swapped to be the opposite throughout.
Disclaimer 1: This is only an example I made up to show step order and opposite terms. This is not necessarily how you would write about machinery that uses gas.
Disclaimer 2: Consider whether the last step of "replace" should involve turning it back on. In complicated systems, things may need to be turned on in a particular order. Or there could be other reasons not to blindly turn something on. In this example, I left it in for illustrative purposes.
INITIAL SETUP
Personnel Required: Maintainer (2)
Prerequisites: Pressure valve on helium tank is shut off and pressure gauge reads zero.
Remove InflaTech BAL006 Balloon Machine
WARNING
The InflaTech BAL006 balloon machine requires a two-person lift. Items weighing over 20.5 kilograms (45 pounds) shall be placed for two-person handling.
Replace InflaTech BAL006 Balloon Machine
With this idea in mind, you can write one of them to completion, then for the other
you can trace those steps in reverse order and write the opposite or reverse command.
Do this, then check
your work for any breaks in the logic. It should be pretty close to what you want. Add figures
(images) when time permits: both photographs and cabling diagrams are particularly helpful here.
Don't forget small items like screws. A brief extra sentence like "Set screws aside." is sufficient.
Troubleshooting topics are for isolating faults in hardware or software. The text content is organized into symptoms, malfunctions, and corrective actions.
what the user observes (e.g., the balloon doesn't inflate).the failure condition that explains the symptom (e.g., the
balloon is
ripped).how to resolve the malfunction.
If another malfunction exists for the symptom, the final step can be "If problem is not resolved, continue to next malfunction".
If another malfunction does not exist for the symptom, the final step can be "Remove and replace XXX".
This method helps tie the troubleshooting elements together so the reader doesn't hit a dead end.
Note: In my experience, when a troubleshooting topic contains phone numbers and/or email addresses, I usually get told they're outdated and to remove them. If you encounter these things, remember to ask if they're still valid.
There can be more than one symptom per troubleshooting topic, but they are usually related somehow. In this example, there is only one symptom.
The military way lists them out vertically... but the commercial way uses a table... whichever way you choose, be consistent and use the full hierarchy: symptom, malfunction, corrective actions.
Disclaimer: This is only an example I made up to show the general format of a troubleshooting topic. This is not necessarily how you would write about machinery that uses gas.
Troubleshooting the InflaTech BAL006 Balloon Machine
INITIAL SETUP
Personnel required: Maintainer (1)
SYMPTOM
Balloon is not inflating.
MALFUNCTION
Balloon is damaged.
CORRECTIVE ACTIONS
MALFUNCTION
Inflate mode is not enabled.
CORRECTIVE ACTIONS
MALFUNCTION
External or internal device fault.
CORRECTIVE ACTIONS
If caution readout blinks amber once, repeating, this indicates the machine is not receiving helium. Restore helium as follows:
Troubleshooting the InflaTech BAL006 Balloon Machine
INITIAL SETUP
Personnel required: Maintainer (1)
| Symptom | Malfunction | Corrective Actions |
|---|---|---|
| Balloon is not inflating. | Balloon is damaged. |
|
| Inflate mode is not enabled. |
|
|
| External or internal device fault. |
|
Darwin Information Typing Architecture (DITA) is an open XML standard for topic-based authoring. This code interfaces with the DITA Open Toolkit to generate custom output of all kinds, including MS Word files.
DITA code structures data inside
"tags". For example, <p>This is a paragraph.</p>.
<p> is the opening tag.</p> is the closing tag.There are numerous different tags. The tags designate the character data's role in the document and its position in the hierarchy as standardized by the DTD's rules.
DITA code is just structured data waiting to be transformed.
A ".ditamap" file lists a series of <topicref> (topic reference) tags with hyperlinks to the .dita files that comprise a whole document. The order from top to bottom will match the output. And so will the nesting (i.e., when a topic has a topic nested inside it, the output will have Section 1 followed by Section 1.1).
A ".dita" file contains the title and body of a topic.
The Document Type Definition (DTD) declared at the top of every .ditamap and .dita file defines the rules that XML must follow in order to "validate" against the DITA standard. Code that validates can be transformed. Code that does not validate cannot be transformed.
There are two (2) document types I use: map and topic.
DITAMAP DTD DECLARATION
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
TOPIC DTD DECLARATION
<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
These .dtd files are hosted on the Internet. You don't need to read the .dtd files.
A code editor like OxygenXML can tell you when something in your code does not validate, either with red squigglies or with error messages in the console when you try to validate.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
<map>
<title>Sample DITA Map</title>
<topicref href="1/1000-Introduction.dita"/>
<topicref href="2/2000-Installation.dita">
<topicref href="2/2005-Requirements.dita"/>
<topicref href="2/2010-Setup.dita"/>
</topicref>
<topicref href="3/3000-Usage.dita"/>
</map>
The first line declares the file as XML. It's always the same even for non-DITA XML files.
The second line declares the DTD for ditamap, which is map.dtd.
The third line is the <map> tag. Note the closing tag at the bottom as well. The
content between the opening and closing tags is "nested" which causes it to indent.
Then you have the <title> and <topicref> tags. Each topicref
has an
href attribute with a directory to the .dita topic. In this example, imagine folders named 1, 2, and
3.
The forward slash character (/) indicates the .dita files are inside those folders. The leading
numbers
in the file names (e.g., 1000-, 2000-, 2005-) are the naming convention I use to order my files. It
starts with chapter number, then increments the ending number by 5 for ordering. This leaves room
for
a
few extra files to be added later in-between.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
<topic>
<!-- This is a comment -->
<title>Sample DITA Topic</title>
<body>
<p>This is the first paragraph.</p>
<p>This is the second paragraph.</p>
<ol>
<li>
<p>First ordered step.</p>
</li>
<li>
<p>Second ordered step.</p>
</li>
<li>
<p>Third ordered step.</p>
</li>
</ol>
<ul>
<li>
<p>First unordered list item.</p>
</li>
<li>
<p>Second unordered list item.</p>
</li>
<li>
<p>Third unordered list item.</p>
</li>
</ul>
<fig>
<title>Sample Image</title>
<image href="images/sample-image.png" align="center"/>
</fig>
<note type="warning">This is a warning.</note>
<note type="caution">This is a caution.</note>
<note>This is a note.</note>
<simpletable>
<sthead>
<stentry>This is the first column header</stentry>
<stentry>This is the second column header</stentry>
</sthead>
<strow>
<stentry>First row, first column cell</stentry>
<stentry>First row, second column cell</stentry>
</strow>
<strow>
<stentry>Second row, first column cell</stentry>
<stentry>Second row, second column cell</stentry>
</strow>
</simpletable>
</body>
</topic>
The first line declares the file as XML. It's always the same even for non-DITA XML files.
The second line declares the DTD for topic, which is topic.dtd.
The third line is the <topic> tag. Note the closing tag at the bottom as well.
The
content between the opening and closing tags is "nested" which causes it to indent.
The fourth line is a comment. The character data in a comment will not display in the output.
Then you have the <title> and <body> tags. The title of a topic
will appear in a table of contents or whatever other method of navigation. The body tag is merely a
container for everything else; again, note the closing tag at the bottom as well.
Then you have <p> and <ol> and <ul>. You can
nest lists inside of each other, too. To do this, position the nested list after the paragraph
inside a list item.
Then you have <fig>. It has its own title and an image. You can have more than one
image inside one figure. Notice that, since the image tag doesn't have character data, it doesn't
need both opening and closing tags; it just ends with />
Then you have <note> for warnings, cautions, and notes. Newer versions of DITA
have <warning> and <caution> which are also valid.
Then you have <simpletable>. Take a look at the general structure. In practice, I
nest
the simpletable inside a section so I can give it a title.
Note: I am writing this from a Windows perspective. If you do not have access to a Windows computer, disregard this section.
Note: This lesson uses the com.elovirta.ooxml plugin. As of this writing, the last major update was in 2020. It works well for me but may not be the most modern free tool.
Download the DITA OT here: https://www.dita-ot.org/
Info about the com.elovirta.ooxml plugin is available here: https://github.com/jelovirt/com.elovirta.ooxml
The GitHub install instructions say to use this command:
$ dita --install com.elovirta.ooxml
Before that will work, though, I believe you'll need to add your dita install's bin folder to your path environment variable:
If you're having trouble, let me know.
Keep in mind this is NOT an app; rather, it is a toolkit for developing functionality yourself based on pre-built templates. As for the functionality, it has integration with OxygenXML Editor and seems to be included with it, which simplifies the "transformation scenario" somewhat. But, since that is a paid software, I'll show you how to use the DITA OT to transform your dita code into an MS Word file (.docx) without any paid software.
After installing the DITA OT and "com.elovirta.ooxml" plugin, navigate to plugins > com.elovirta.ooxml > docx > word.
The files I recommend checking out here are:
Take a look at lines containing xsl:template match. This is XSLT code that defines a
chunk of transformation logic.
First look at
<xsl:template match="*[contains(@class, ' map/map ')]" mode="root">.
As you can see, this is where the transformation begins by targeting <map>
(the outermost tag of a
.ditamap file). This block of code pulls in the contents of template matches below (such as
"cover" and "body") via xsl:apply-templates.
Those
template matches are defined below.
Next, take a look at the various tags you see that begin with w:. This is Office
Open XML (OOXML).
| Tag | Name | Description |
|---|---|---|
| w:document | Document | Root element of a WordprocessingML document. |
| w:body | Body | Contains the main document content. |
| w:p | Paragraph | Represents a paragraph. |
| w:pPr | Paragraph Properties | Formatting and layout properties for a paragraph. |
| w:r | Run | A region of text with the same formatting. |
| w:rPr | Run Properties | Formatting properties for a run (font, size, bold, etc.). |
| w:t | Text | The actual text content inside a run. |
| w:br | Line Break | Forces a line break within a paragraph. |
| w:sectPr | Section Properties | Defines section-level settings like page size and margins. |
| w:pgSz | Page Size | Specifies the width and height of the page. |
| w:headerReference | Header Reference | Links a section to a header part. The named r:id attributes are defined inside com.elovirta.ooxml-master > resources > Normal.docx and are accessible only by converting it to .zip and inspecting its contents. |
| w:footerReference | Footer Reference | Links a section to a footer part. The named r:id attributes are defined inside com.elovirta.ooxml-master > resources > Normal.docx and are accessible only by converting it to .zip and inspecting its contents. |
I'll try to describe how OOXML works... please look at the code inside the templace match blocks and see if you understand what I'm saying:
<w:p>) begin with a Paragraph Properties block
(<w:pPr>).<w:r>). Runs begin with a Run Properties
block (<w:rPr>).<w:t>). For the text, the default formatting
will be the paragraph
properties, and the run properties override the paragraph properties
whenever they conflict.<w:sectPr>) go at the END / the BOTTOM of a template
match. This block of
code defines the page size, headers, and footers of the content ABOVE it.<w:sz w:val="24">) is recorded in half-points:
<w:rPr><w:sz w:val="24"/></w:rPr> is describing a
12-point font.
<w:pgSz>) defines the page size like
<w:w="12240" w:h="15840"> ... these values are
"twentieth of an Imperial point" values (or "twips"). 1440 twips = 1 inch. In this
example, if you swap the width and height, the section will have a landscape
orientation.
The order in which templates are applied within
<xsl:template match="*[contains(@class, ' map/map ')]" mode="root">
determines
the whole content of the Word file export. That is where everything comes from; editing the root
gives you immediate control of your transformation.
The mode "cover" defines the "front matter" of the document.
The mode "toc" defines the table of contents. That one is actually defined in document.toc.xsl
where you can look for a <xsl:value-of> line to enter your table of contents
field code.
The mode "body" defines all topics. The template match implements logic from document.topic.xsl. This is where you can customize your document a lot. You can add new dita tags of your own called "processing instructions" and define what they do.
You can make new templates and modes here as well. I made a new one called "end" that adds a few extra pages after the body of the document.
document.topic.xsl handles the transformation of each DITA
<topic> and its children into paragraphs, headings, lists,
images, and other body elements.
Try searching for @class, ' topic/ and see if you recognize what the template
matches and other code is doing. The first one to be processed is
<xsl:template match="*[contains(@class, ' topic/topic ')]"> which is the
root template for every topic.
Key things you'll see here:
topic/title)
<topic/p> becomes a
<w:p> with <w:r> runs inside for text, bold,
italic, etc. (using modes like "inline-style" or "block-style")
Here are some processing instructions I made and use frequently.
In your .dita, with processing instructions, you write it in like <?tab?>. The
ones whose content is a run (e.g., the tab and horizontal line ones below) must be placed inside
a para
<p> or they won't
work. That's because the processing instruction inserts it literally, without doing anything
else under the hood to fix it for you, and runs need to be inside paragraphs.
<xsl:template match="processing-instruction('tab')">
<w:r>
<w:tab/>
</w:r>
</xsl:template>
<xsl:template match="processing-instruction('horizontal-line')">
<w:r>
<w:pict>
<xsl:choose>
<xsl:when test="ancestor::topic[1][@outputclass = 'portrait']">
<v:rect style="width:6.5in;height:1pt" o:hralign="center" o:hrstd="t" o:hrnoshade="t"
o:hr="t" fillcolor="black [3213]" stroked="f"/>
</xsl:when>
<xsl:when test="ancestor::troubleshooting[1][@outputclass = 'portrait']">
<v:rect style="width:6.5in;height:1pt" o:hralign="center" o:hrstd="t" o:hrnoshade="t"
o:hr="t" fillcolor="black [3213]" stroked="f"/>
</xsl:when>
<xsl:when test="ancestor::topic[1][@outputclass = 'landscape']">
<v:rect style="width:9in;height:1pt" o:hralign="center" o:hrstd="t" o:hrnoshade="t"
o:hr="t" fillcolor="black [3213]" stroked="f"/>
</xsl:when>
<xsl:when test="ancestor::troubleshooting[1][@outputclass = 'landscape']">
<v:rect style="width:9in;height:1pt" o:hralign="center" o:hrstd="t" o:hrnoshade="t"
o:hr="t" fillcolor="black [3213]" stroked="f"/>
</xsl:when>
<xsl:otherwise>
<v:rect style="width:468pt;height:1pt" o:hralign="center" o:hrstd="t" o:hrnoshade="t"
o:hr="t" fillcolor="black [3213]" stroked="f"/>
</xsl:otherwise>
</xsl:choose>
</w:pict>
</w:r>
</xsl:template>
<xsl:template match="processing-instruction('page-break')">
<w:r>
<w:br w:type="page"/>
</w:r>
</xsl:template>
Change the file extension of this file to .zip to inspect and modify its contents. When asked if you want to save a backup, always say no.
When you're done modifying Normal.zip, always change it back to Normal.docx or it won't work.
Also, never open this file in Word itself, especially with autosave turned on. Doing this will scramble and delete anything you have customized. I recommend keeping backups here in a folder.
This Word file contains the header and footer information. It links them via named ids to the
w:sectPr
parts of document.root.xsl, specifically the r:id attributes of
w:headerReference and
w:footerReference.
The pipeline is like this:
<w:headerReference w:type="default" r:id="rId8"/>.
<Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/>
This same method also applies for images you wish to implement outside of the document body. For example, if you want to add a logo to the cover page, the .png file goes in Normal.docx > media and similarly has its own relationship id.
The OOXML for the image, then, in document.root.xsl is something like this:
Look for this: r:embed="imageLogo"
THAT is the id that traces to _rels.
<w:drawing>
<wp:inline
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<wp:extent cx="1143000" cy="1143000"/>
<wp:docPr id="1" name="imageLogo"/>
<a:graphic>
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic>
<pic:nvPicPr>
<pic:cNvPr id="0" name="imageLogo"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="imageLogo"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="1143000" cy="1143000"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
This only works if you have dita install's bin folder added to the system environment path variable.
This set of console scripts tells you if it is working: dita --version and
dita --list-plugins and dita --formats
This console script executes the transformation procedure:
dita -i yourmap.ditamap -f docx -o output-folder
In Microsoft Word, field codes display contextual information that can be updated over time — such as a table of contents — or specific types of variables such as page numbers and dates.
Important: A newly created field code must be updated at least once
before its output becomes visible. Otherwise it appears blank.
To toggle field codes, first click anywhere in the main document body, then press [ALT] + [F9]. The field code toggles between displaying the code and its designated output.
To create a new field code, first click where you want to place it in the main document body, then press [CTRL] + [F9]. It will initially appear blank.
To update a field code, right-click the field code and select Update Field. (You may need to right-click what initially appears to be nothing.)
{ DATE \@ "dd MMMM, yyyy" } → 02 April, 2025
{ DATE \@ "dd/MM/yy" } → 02/04/25
{ TIME \@ "h:mm AM/PM" } → 11:04 AM
{ TIME \@ "HH:mm:ss" } → 11:04:30
d = dayM = monthy = yearH = hour (24h)h = hour (12h)m = minutes = secondAM/PM = AM or PM indicator{ PAGE } → current page number
{ PAGE \* ARABIC } → 9
{ PAGE \* roman } → ix
{ NUMPAGES }
{ NUMPAGES \* ARABIC } → 42
{ NUMPAGES \* roman } → xlii
The format for this field code includes an identifier (such as Figure) and switches (such as
\n which increments the
number and \r 1 which resets the number to one). After SEQ, express the format like
this:
{ SEQ Figure \n } → 1, 2, 3…
{ SEQ Figure \r 1 } → reset to 1
Note that the identifier does not display with the output. It is like an id enabling more than one sequence to co-exist.
{ TOC \o "1-4" \h } → Headings 1-4 with hyperlinks
{ TOC \t "Caption,1" } → All Caption-style paragraphs at level
1
{ TOC \o "1-4" \t "TitleHowToUse,1,Appendix1,1,Appendix2,2" }
→
The table of contents contains Heading 1, Heading 2, Heading 3, and Heading 4. It also contains
all
paragraphs with the TitleHowToUse, Appendix1, and Appendix2 paragraph styles, at depth levels 1,
1,
and 2, respectively.
Note that a paragraph with no content still has a paragraph style applied to it. Be wary of blank TOC entries.
Add \* MERGEFORMAT to allow manual formatting changes to persist after updates.
Regular expressions (regex) are powerful patterns that, using concise symbolic notation, greatly expand find/replace functionality. They help with bulk processing of more than one file at a time, and they can search, find, and manipulate text strings by describing specific rules or structures. Indeed this has the potential to make a time-consuming task a hundred times easier.
A simple example is (?si)\b(he|his|him|himself|she|hers|her|herself)\b. This searches
for all 8 words at the same time!
Learn more here: RegexOne interactive lessons and regex101.com tester.
| Token | Matches |
|---|---|
\d |
one digit (0–9) |
\w |
one word character (letter, digit, underscore) |
\s |
one whitespace character |
. |
any character except line break |
\. |
literal period |
\ |
escape the next character |
| Token | Meaning |
|---|---|
+ |
1 or more |
* |
0 or more |
? |
0 or 1 |
{3} |
exactly 3 |
{2,4} |
2 to 4 |
{3,} |
3 or more |
lazy? |
make previous quantifier lazy (e.g. .*?) |
| Operator | Effect |
|---|---|
| |
OR |
(…) |
capturing group (use \1, \2… in replacement) |
(?:…) |
non-capturing group |
| Pattern | Matches |
|---|---|
[abc] |
a, b, or c |
[a-z] |
any lowercase letter |
[^0-9] |
anything not a digit |
| Anchor | Meaning |
|---|---|
^ |
start of string |
$ |
end of string |
\b |
word boundary |
<title>\d+\.\s+(.*?)</title> →
<title>\1</title>[A-Z](?![A-Z])[^\.!?]*?,[^\.!?]+?,[^\.!?]+?,[^\.!?]+?,[^\.!?]*?[\.!?](?:\s+|$)\b(\w+)\s+\1\bPython scripts can automate tasks, turning days of work into a few seconds. I invite you to consider making your own scripts after exploring what the libraries are capable of.
Download Python for free on the Microsoft Store. This will also give you an app with which to open the Python console.
By installing libraries onto your computer via the terminal and importing them at the top of your script, you greatly expand the scripts' capabilities.
The libraries are "dependencies"; if a script uses functions from a library that is not imported first, or is imported but not yet installed, the script will fail. Therefore, remember that you need to both install AND import the Python libraries you are using.
Here is a list of libraries I used in my example script below, which extracts acronyms from a .docx or .pdf file:
| Library / Import | Description | Needs pip install? |
|---|---|---|
from docx import Document |
Creates, reads, modifies and saves Microsoft Word (.docx) files | Yes — pip install python-docx |
from itertools import chain |
Provides tools for working with iterators (chain, cycle, combinations, groupby, etc.) | No |
import pandas as pd |
Provides tools for working with data manipulation and analysis (DataFrames, Series, CSV/Excel, groupby, merge, etc.) | Yes — pip install pandas |
import os |
Provides the essential Operating System interface to navigate directories and create files in them. | No |
import PyPDF2 |
Reads, modifies, and extracts text from PDF files. | Yes — pip install PyPDF2
|
import tkinter as tk |
Provides tools for building a software GUI elements (windows, widgets, dialogs). | No |
from tkinter import filedialog, messagebox |
Imports tkinter submodules — file open/save dialogs + message/pop-up boxes | No |
import re |
Provides tools for working with regular expressions (match, search, replace, split, etc.) | No |
import unicodedata |
Provides the essential Unicode database access (normalization, decomposition, character properties, etc.) | No |
engine="openpyxl" |
Creates, reads, modifies and saves Microsoft Excel (.xlsx) files Note this did not require an import because pandas does it by calling an engine. |
Yes — pip install openpyxl |
pip install python-docxpip install pandaspip install openpyxlpip install PyPDF2.import os os.chdir(r"XXX") where XXX is the directory to the folder containing
main.pyexec(open("main.py").read())
from docx import Document
from itertools import chain
import pandas as pd
import os
import PyPDF2
import tkinter as tk
from tkinter import filedialog, messagebox
import re
import unicodedata
def read_acronym(file_path: str) -> dict:
df = pd.read_excel(file_path, engine="openpyxl", header=None, names=["w", "a"])
data_dict = {}
for i, record in df.iterrows():
key = str(record.iloc[0]).strip() # Strip whitespace from Excel keys
data_dict[key] = str(record.iloc[1])
return data_dict
def normalize_text(text: str) -> str:
"""Normalize text by standardizing slashes and removing extra whitespace."""
if not text:
return text
# Replace Unicode variants of slash with standard forward slash
text = unicodedata.normalize('NFKC', text).replace('\u2044', '/').replace('\u2215', '/')
# Remove extra whitespace and normalize spaces
text = ' '.join(text.split())
return text
def read_document(doc_file: str) -> list:
text_list = []
file_extension = os.path.splitext(doc_file)[1].lower()
if file_extension == '.docx':
doc = Document(doc_file)
# Regex pattern to match words, including those with slashes, hyphens, or dots
pattern = r'\b[\w/.-]+\b'
# Helper function to process text and log for debugging
def process_text(source: str, text: str):
raw_text = text
text = normalize_text(text)
# print(f"DEBUG: Raw text in {source}: '{raw_text}'")
if text:
words = re.findall(pattern, text)
for word in words:
if word:
cleaned_word = word.replace(",", "").replace(".", "").replace("(", "").replace(")", "")
if cleaned_word:
text_list.append(cleaned_word)
# print(f"DEBUG: Found word '{cleaned_word}' in {source}")
# Read document properties (metadata) like TITLE
core_properties = doc.core_properties
properties = [
("title", core_properties.title),
("author", core_properties.author),
("subject", core_properties.subject),
("keywords", core_properties.keywords),
("comments", core_properties.comments),
("category", core_properties.category),
]
for prop_name, prop_value in properties:
if prop_value: # Only process non-empty properties
process_text(f"document property ({prop_name})", prop_value)
# Read main body paragraphs
for para in doc.paragraphs:
process_text("main body paragraph", para.text)
# Read tables
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text("main body table", paragraph.text)
# Read headers and footers from all sections
for i, section in enumerate(doc.sections):
# Process headers (first page, odd pages, even pages)
for header_type, header in [
("default header", section.header),
("first page header", section.first_page_header),
("even page header", section.even_page_header)
]:
# print(f"DEBUG: Section {i+1} {header_type} is_linked_to_previous: {header.is_linked_to_previous}")
for paragraph in header.paragraphs:
process_text(f"section {i+1} {header_type}", paragraph.text)
# Process tables in headers
for table in header.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text(f"section {i+1} {header_type} table", paragraph.text)
# Process footers (first page, odd pages, even pages)
for footer_type, footer in [
("default footer", section.footer),
("first page footer", section.first_page_footer),
("even page footer", section.even_page_footer)
]:
# print(f"DEBUG: Section {i+1} {footer_type} is_linked_to_previous: {footer.is_linked_to_previous}")
for paragraph in footer.paragraphs:
process_text(f"section {i+1} {footer_type}", paragraph.text)
# Process tables in footers
for table in footer.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text(f"section {i+1} {footer_type} table", paragraph.text)
elif file_extension == '.pdf':
try:
with open(doc_file, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
for i, page in enumerate(pdf_reader.pages):
text = page.extract_text()
if text:
text = normalize_text(text)
words = re.findall(r'\b[\w/.-]+\b', text)
for word in words:
if word:
cleaned_word = word.replace(",", "").replace(".", "").replace("(", "").replace(")", "")
if cleaned_word:
text_list.append(cleaned_word)
# print(f"DEBUG: Found word '{cleaned_word}' in PDF page {i+1}")
except Exception as e:
raise Exception(f"Error reading PDF file {doc_file}: {str(e)}")
else:
raise ValueError(f"Unsupported file extension {file_extension}. Only .docx and .pdf are supported.")
return text_list
def bigram_generator(text_list: list) -> list:
bigrams = []
for i, item in enumerate(text_list):
if i + 1 == len(text_list):
break
bigram = str(item) + " " + str(text_list[i + 1])
bigrams.append(bigram)
# print(f"DEBUG: Generated bigram '{bigram}'")
return bigrams
def normalize_dict_key(key: str) -> str:
"""Normalize dictionary keys for comparison."""
return normalize_text(key)
if __name__ == "__main__":
def run_extraction(acronym_file, doc_file, output_dir):
print("➡" * 4 + " Program Started " + "⬅" * 4)
try:
# Check if files exist and are accessible
if not os.path.exists(acronym_file):
raise FileNotFoundError(f"Acronym file {acronym_file} not found")
if not os.path.isfile(acronym_file):
raise FileNotFoundError(f"{acronym_file} exists but is not a file")
if not os.access(acronym_file, os.R_OK):
raise PermissionError(f"Cannot read {acronym_file} due to permissions")
if not os.path.exists(doc_file):
raise FileNotFoundError(f"Document file {doc_file} not found")
if not os.path.isfile(doc_file):
raise FileNotFoundError(f"{doc_file} exists but is not a file")
if not os.access(doc_file, os.R_OK):
raise PermissionError(f"Cannot read {doc_file} due to permissions")
if not os.path.exists(output_dir):
try:
os.mkdir(output_dir)
print("Created directory:", output_dir)
except PermissionError as e:
raise PermissionError(f"Cannot create directory {output_dir}: {e}")
if not os.access(output_dir, os.W_OK):
raise PermissionError(f"Cannot write to directory {output_dir}")
# Read acronym file
acronym_dict = read_acronym(acronym_file)
print("➡ Excel read successfully::\t{}".format(acronym_file))
# Add plurals of acronyms
acronym_plurals_1 = {normalize_dict_key(key + "s"): value for key, value in acronym_dict.items()}
acronym_plurals_2 = {normalize_dict_key(key + "es"): value for key, value in acronym_dict.items()}
acronym_dict = {normalize_dict_key(key): value for key, value in acronym_dict.items()}
acronym_dict = {**acronym_dict, **acronym_plurals_1, **acronym_plurals_2}
# Read document
text_list = read_document(doc_file)
print("➡ Document read successfully::\t{}".format(doc_file))
# Generate bigrams
bigrams = bigram_generator(text_list)
output_dict = {"word": [], "acronym": []}
items_list = list(chain(bigrams, text_list))
for item in acronym_dict.keys():
if item in items_list:
output_dict["word"].append(item)
output_dict["acronym"].append(acronym_dict[item])
# print(f"DEBUG: Matched acronym '{item}'")
# Define output file
output_file = os.path.join(output_dir, "output_acronyms_list.xlsx")
if os.path.exists(output_file) and not os.access(output_file, os.W_OK):
raise PermissionError(f"Cannot write to file {output_file} (possibly open or read-only)")
output_df = pd.DataFrame(output_dict)
output_df["word"] = output_df["word"].apply(lambda x: x.rstrip("es").rstrip("s"))
output_df = output_df.sort_values("word")
output_df.to_excel(output_file, index=False, header=None)
print("↕" * 4 + " Output Generated Successfully " + "↕" * 4)
return f"Output generated successfully at:\n{output_file}"
except Exception as e:
print("↕" * 4 + " Error Occurred:\t{}".format(e) + "↕" * 4)
raise e
class AcronymApp:
def __init__(self, root):
self.root = root
self.root.title("Acronym Extractor")
self.root.geometry("600x400")
# Variables to store file paths
self.acronym_file = tk.StringVar()
self.doc_file = tk.StringVar()
self.output_dir = tk.StringVar()
# GUI Elements
tk.Label(root, text="Select Acronym Excel File:").pack(pady=10)
tk.Entry(root, textvariable=self.acronym_file, width=50).pack()
tk.Button(root, text="Browse", command=self.browse_acronym_file).pack(pady=5)
tk.Label(root, text="Select Document File (.docx or .pdf):").pack(pady=10)
tk.Entry(root, textvariable=self.doc_file, width=50).pack()
tk.Button(root, text="Browse", command=self.browse_doc_file).pack(pady=5)
tk.Label(root, text="Select Output Directory:").pack(pady=10)
tk.Entry(root, textvariable=self.output_dir, width=50).pack()
tk.Button(root, text="Browse", command=self.browse_output_dir).pack(pady=5)
tk.Button(root, text="Run Acronym Extraction", command=self.run_extraction).pack(pady=20)
def browse_acronym_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx *.xls")])
if file_path:
self.acronym_file.set(file_path)
def browse_doc_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Document files", "*.docx *.pdf")])
if file_path:
self.doc_file.set(file_path)
def browse_output_dir(self):
dir_path = filedialog.askdirectory()
if dir_path:
self.output_dir.set(dir_path)
def run_extraction(self):
try:
# Validate inputs
acronym_file = self.acronym_file.get()
doc_file = self.doc_file.get()
output_dir = self.output_dir.get()
if not acronym_file or not doc_file or not output_dir:
messagebox.showerror("Error", "Please select all required files and directory.")
return
# Run extraction
success_message = run_extraction(acronym_file, doc_file, output_dir)
messagebox.showinfo("Success", success_message)
except Exception as e:
messagebox.showerror("Error", f"An error occurred: {str(e)}")
print("➡" * 4 + " Program Closed " + "⬅" * 4)
root = tk.Tk()
app = AcronymApp(root)
root.mainloop()
if __name__ == "__main__":.def run_extraction it
validates that all required paths
exist and are accessible.
if __name__ == "__main__":
def run_extraction(acronym_file, doc_file, output_dir):
print("➡" * 4 + " Program Started " + "⬅" * 4)
try:
# Check if files exist and are accessible
if not os.path.exists(acronym_file):
raise FileNotFoundError(f"Acronym file {acronym_file} not found")
if not os.path.isfile(acronym_file):
raise FileNotFoundError(f"{acronym_file} exists but is not a file")
if not os.access(acronym_file, os.R_OK):
raise PermissionError(f"Cannot read {acronym_file} due to permissions")
if not os.path.exists(doc_file):
raise FileNotFoundError(f"Document file {doc_file} not found")
if not os.path.isfile(doc_file):
raise FileNotFoundError(f"{doc_file} exists but is not a file")
if not os.access(doc_file, os.R_OK):
raise PermissionError(f"Cannot read {doc_file} due to permissions")
if not os.path.exists(output_dir):
try:
os.mkdir(output_dir)
print("Created directory:", output_dir)
except PermissionError as e:
raise PermissionError(f"Cannot create directory {output_dir}: {e}")
if not os.access(output_dir, os.W_OK):
raise PermissionError(f"Cannot write to directory {output_dir}")
def read_acronym it "reads" (adds) the acronym Excel file's data
into a "dictionary" (set of key-value pairs). The
first column (the acronym) becomes the key, and the second column (the definition) becomes the
value. Keys are stripped of whitespace here.
# Read acronym file
acronym_dict = read_acronym(acronym_file)
↓↓↓
def read_acronym(file_path: str) -> dict:
df = pd.read_excel(file_path, engine="openpyxl", header=None, names=["w", "a"])
data_dict = {}
for i, record in df.iterrows():
key = str(record.iloc[0]).strip() # Strip whitespace from Excel keys
data_dict[key] = str(record.iloc[1])
return data_dict
# Add plurals of acronyms
acronym_plurals_1 = {normalize_dict_key(key + "s"): value for key, value in acronym_dict.items()}
acronym_plurals_2 = {normalize_dict_key(key + "es"): value for key, value in acronym_dict.items()}
acronym_dict = {normalize_dict_key(key): value for key, value in acronym_dict.items()}
acronym_dict = {**acronym_dict, **acronym_plurals_1, **acronym_plurals_2}
def read_documentit reads the document's paragraphs, tables, and
headers / footers. This step supports both .docx and .pdf files.
# Read document
text_list = read_document(doc_file)
print("➡ Document read successfully::\t{}".format(doc_file))
↓↓↓
def read_document(doc_file: str) -> list:
text_list = []
file_extension = os.path.splitext(doc_file)[1].lower()
if file_extension == '.docx':
doc = Document(doc_file)
# Regex pattern to match words, including those with slashes, hyphens, or dots
pattern = r'\b[\w/.-]+\b'
# Helper function to process text and log for debugging
def process_text(source: str, text: str):
raw_text = text
text = normalize_text(text)
# print(f"DEBUG: Raw text in {source}: '{raw_text}'")
if text:
words = re.findall(pattern, text)
for word in words:
if word:
cleaned_word = word.replace(",", "").replace(".", "").replace("(", "").replace(")", "")
if cleaned_word:
text_list.append(cleaned_word)
# print(f"DEBUG: Found word '{cleaned_word}' in {source}")
# Read document properties (metadata) like TITLE
core_properties = doc.core_properties
properties = [
("title", core_properties.title),
("author", core_properties.author),
("subject", core_properties.subject),
("keywords", core_properties.keywords),
("comments", core_properties.comments),
("category", core_properties.category),
]
for prop_name, prop_value in properties:
if prop_value: # Only process non-empty properties
process_text(f"document property ({prop_name})", prop_value)
# Read main body paragraphs
for para in doc.paragraphs:
process_text("main body paragraph", para.text)
# Read tables
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text("main body table", paragraph.text)
# Read headers and footers from all sections
for i, section in enumerate(doc.sections):
# Process headers (first page, odd pages, even pages)
for header_type, header in [
("default header", section.header),
("first page header", section.first_page_header),
("even page header", section.even_page_header)
]:
# print(f"DEBUG: Section {i+1} {header_type} is_linked_to_previous: {header.is_linked_to_previous}")
for paragraph in header.paragraphs:
process_text(f"section {i+1} {header_type}", paragraph.text)
# Process tables in headers
for table in header.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text(f"section {i+1} {header_type} table", paragraph.text)
# Process footers (first page, odd pages, even pages)
for footer_type, footer in [
("default footer", section.footer),
("first page footer", section.first_page_footer),
("even page footer", section.even_page_footer)
]:
# print(f"DEBUG: Section {i+1} {footer_type} is_linked_to_previous: {footer.is_linked_to_previous}")
for paragraph in footer.paragraphs:
process_text(f"section {i+1} {footer_type}", paragraph.text)
# Process tables in footers
for table in footer.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
process_text(f"section {i+1} {footer_type} table", paragraph.text)
elif file_extension == '.pdf':
try:
with open(doc_file, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
for i, page in enumerate(pdf_reader.pages):
text = page.extract_text()
if text:
text = normalize_text(text)
words = re.findall(r'\b[\w/.-]+\b', text)
for word in words:
if word:
cleaned_word = word.replace(",", "").replace(".", "").replace("(", "").replace(")", "")
if cleaned_word:
text_list.append(cleaned_word)
# print(f"DEBUG: Found word '{cleaned_word}' in PDF page {i+1}")
except Exception as e:
raise Exception(f"Error reading PDF file {doc_file}: {str(e)}")
else:
raise ValueError(f"Unsupported file extension {file_extension}. Only .docx and .pdf are supported.")
return text_list
def bigram_generator it generates two-word pairs called bigrams to
help
detect two-word acronyms.
# Generate bigrams
bigrams = bigram_generator(text_list)
↓↓↓
def bigram_generator(text_list: list) -> list:
bigrams = []
for i, item in enumerate(text_list):
if i + 1 == len(text_list):
break
bigram = str(item) + " " + str(text_list[i + 1])
bigrams.append(bigram)
# print(f"DEBUG: Generated bigram '{bigram}'")
return bigrams
output_dict = {"word": [], "acronym": []}
items_list = list(chain(bigrams, text_list))
for item in acronym_dict.keys():
if item in items_list:
output_dict["word"].append(item)
output_dict["acronym"].append(acronym_dict[item])
# print(f"DEBUG: Matched acronym '{item}'")
# Define output file
output_file = os.path.join(output_dir, "output_acronyms_list.xlsx")
if os.path.exists(output_file) and not os.access(output_file, os.W_OK):
raise PermissionError(f"Cannot write to file {output_file} (possibly open or read-only)")
rstrip("es").rstrip("s") portion removes the plural endings that were added earlier
so the output
shows the base acronym.
output_df = pd.DataFrame(output_dict)
output_df["word"] = output_df["word"].apply(lambda x: x.rstrip("es").rstrip("s"))
output_df = output_df.sort_values("word")
output_df.to_excel(output_file, index=False, header=None)
print("↕" * 4 + " Output Generated Successfully " + "↕" * 4)
return f"Output generated successfully at:\n{output_file}"
Source: ATD Mentor Toolkit, pages 8-9
A Mentor’s guide to helping mentees shine in interviews.
Source: ATD Article
By Robin Ryan
Most definitely yes. In fact, HR recruiter Angela Oakley reveals a shocking thought: “Job interviews are set up to make people feel like a failure. Think about the fact that employers typically see five candidates and four do not get hired. That’s a failure rate of 80 percent. Selling yourself effectively today is everything if you want to land the job, and that includes knowing how to effectively answer the tough questions and present yourself in a professional manner.”
Here are my top five job interview tips to help you excel in today’s marketplace.
Most employers remember only a few things about any given candidate after the interview. The 60-second sell focuses the employer’s attention on your most important attributes. To do this, analyze the job duties, then select your top five selling points—your strongest abilities to do the job. Link these five points together in a few sentences that can be said in 60 seconds. This becomes your verbal business card. Use this tool early in the interview to answer such questions as, “What are your strengths?”
Most hiring managers will write a short report and rank a candidate immediately after they leave the job interview, which is why you need a persuasive closing statement. As you complete the interview, summarize what you’d bring to the job using points from your 60-second sell. This will underscore the strongest reasons for the employer to select you for the job.
Employers want specific examples of your past work performance, so they’re asking hard questions like, "What is a performance area in which your manager wants you to improve?" Your response must be a specific work situation, and you should include what you are doing to improve. Don’t mention something imperative to performing the job. You can discuss the issue, then outline how you solved a problem, learned from a mistake, dealt with a difficult co-worker or employee, and so on.
Contact your network and see if anyone knows anything about the company and the person conducting the interview. Ask for the name of the person who would be your manager and get the correct spelling. Check out the company’s website and read about the company on Glassdoor.com. Go to LinkedIn and read the manager’s profile. Notice any connections you may have missed. Reach out to them to learn any insider information on the manager and the job needs.
Wait for a job offer before you discuss salary. This is when you will be in the most powerful place to negotiate. Most people get stumped when asked about salary and just give their current one. Other candidates bring up money too fast and lose the job because they haven't proven their worth. Too often your salary expectations are too low, convincing the employer that you must not be that good. Women almost always stumble on this issue. Learn what your skills are worth by visiting Payscale.com. Try to delay any questions on salary until you receive an offer, explaining that you need more job information so you can determine what the position requires and what would be fair. If pushed, give a wide salary range. Carefully practice your answers in advance.
Be prepared for your next interview by using these five tips. If nothing else, you’ll be more relaxed and confident, which can help convince potential employers that you’ll represent the company well.
The ATD Mentorship program representative, Laine Istvan, recommends the Farah Sharghi YouTube channel . Disclaimer: I have not reviewed this content; I am merely relaying the recommendation.
She also says, "...one of my favorite ways to practice interviewing is to use the audio feature with ChatGPT. It has been great tool for feedback and coaching. It tells me where I have gaps in my responses or how I can answer more succinctly."
Some interview locations feature perimeter fencing, security checkpoints, and gated vehicle entrances. To avoid wasting time circling the building on the day of your interview, consider visiting the site a few days in advance to locate the main entrance and familiarize yourself with the layout.
Additionally, many secure buildings remain locked and require you to call a posted number or use an intercom to request entry. Plan ahead for these scenarios by allowing extra time. You may need to wait outside exposed to wind, rain, or other weather. If you have delicate hair, consider bringing a comb or brush with you.
Choosing a school or college is a major life decision that involves balancing your wants and needs against practical realities such as cost, location, and your various unique life circumstances and challenges.
The goal is to find schools where you can thrive according to your own goals, limitations, and proclivities. Nobody else can tell you what it means to thrive, not even a mentor, because your life belongs to you and you decide what matters.
Start by reflecting on what you want to achieve and the kind of environment that will help you grow. You may move laterally a couple times before reaching the true path. That is expected and normal. As you search, try to keep an open mind and take a few steps beyond your initial assumptions before ruling out an option. You can ask others if you have a question about something you discovered.
Evaluate the list below. Which things are must-haves? Which things can be flexible? Which things don't matter at all? This exercise will help you build a value-driven mental image, so be honest and think it over.
Now you know what matters to you. Next, to find out which schools align with your goals, try gathering information with these resources:
Take notes and ask targeted questions as needed.
Now you've looked at various schools. Next, categorize schools you're interested in based around your academic profile. You can reference this data with the College Scorecard website I mentioned above.
A balanced approach might include 2 colleges in each category. Apply to multiple schools to keep your options open. You can always adjust your list as you go.
Now you have a preliminary college list. Next, you can color it with data on the financials. The actual price you pay is usually much lower than the published tuition thanks to financial aid. Key steps include:
In the most structured team I've worked in, I had a folder for each CDRL (Contract Data Requirements List) that was a part of the contract (e.g., A001-XXX, A002-XXX, B001-XXX, B002-XXX, C001-XXX, C002-XXX, where XXX is the document type / name).
Inside each of these folders, I had two (2) folders: Working and SubmittedCopies. The Working folder contained the work-in-progress version of the document and any other stuff used to complete it; the SubmittedCopies folder contained the complete version/s of the document. When ready to submit, I emailed the person (whose role was to submit the documents) a list with the directory of the SubmittedCopies folder and the files they should submit.
I appended the submission date to the end of the filename in YYYYMMDD format. The CDRL number was at the beginning, followed by a submission number and revision letter. An example might be: C002-2A-Manual-20260131.docx. In this example...
Naming conventions vary by contract. Again, that was merely an example from my personal experience.
At first, I used TortoiseSVN to sync a local folder with a project folder on the company server. After editing a file stored locally on my computer, I "committed" my changes via right-click > TortoiseSVN > Commit, which caused the server's copy to be replaced with mine. Other people can use right-click > TortoiseSVN > Update to pull any committed changes into their local copy. If a person ever works on their local copy without updating first, it could lead to a conflict. They would need to revert all their work. This can be a troublesome workflow for that reason, but the commits do help to track changes with granularity. An alternative tool is SharePoint or Git.
For collaboration, I used a browser tool called SmartBear Code Collaborator. The interface in the browser displays the .docx or .pdf file but does not support direct edits; rather, it supports assigning individuals the role of reviewer. Then, the reviewers have a limited period of time to read the document and add "pins". The pins contain a message from the reviewer about an error or question and initially appear with red gumballs / bug icons. When all reviewers are done with this, the author then responds - either by answering the question, refuting the error, or correcting the error and re-uploading the document. After two versions of the document have been uploaded, the Code Collaborator view can display two side-by-side copies for the reviewers to compare and contrast. They confirm their requested changes were implemented by setting the pin as resolved, which changes the pin gumball to green.
Again, Code Collaborator supports Word natively for tracking changes, but the author must edit in Word or a code editing software, then re-upload the file to the Code Collaborator review.
This Code Collaborator process was repeated twice for each document submission: we had one review for the Quality Assurance (QA) team, then a second review for the Subject Matter Expert (SME) team. This way, several sets of eyes with different perspectives looked at the document before finally submitting it.
The customer returned their comments in the form of a Comment Resolution Matrix (CRM)
spreadsheet.
Thus, after the author responded to the CRM comments and made any necessary changes, the next
set of
QA and SME reviews would begin, this time with the CRM spreadsheet included as an attachment in
both
Code Collaborator reviews. Usually,
only changes to the requested portions would be appropriate at this stage, since
the
rest of the content was tacitly accepted as correct by not being mentioned in the
CRM.
But there could be exceptions, according to common sense.
If the customer had any comments, the submission was "accepted conditionally" (if not outright "rejected") and required a resubmission.
A comment can either be "administrative" or "substantive". Administrative comments will refer to minor grammar and spelling mistakes, formatting mistakes, and errors on the title page or in the filename. Substantive comments will refer to inaccurate information, data errors, or anything deemed insufficient to meet the document's intent and purpose. If all the substantive comments were not resolved in a resubmission, the document would then need yet another resubmission or it would be rejected.
In practice, holding informal meetings with the customer prior to document submissions can prevent many CRM comments via the wonders of mutual understanding. The less particular the customer is, the fewer CRM comments they will return. It also helps when the customer's reviewer is a native English speaker well versed in the subject matter and the day-to-day particulars of the project.
Agile is a philosophy and set of values outlined in the so-called "2001 Agile Manifesto". It
emphasizes
iterative development, customer collaboration, and delivering (or just
demonstrating)
value on a set cadence. Agile itself is not the methodology. It's the umbrella term that
includes
frameworks such
as Scrum and Kanban.
A sprint is a "time-boxed unit" of work used specifically within the Scrum framework (1–4 weeks, usually 2 weeks). During a sprint, the team works to complete a selected set of tasks that may or may not produce a "product increment" if that is applicable to the work at hand. If not, it still helps track progress on a macro level. Sprints create a predictable cadence of work from the perspective of leadership.
Agile is the name of a philosophy.
Scrum is a popular framework for applying Agile principles.
A sprint is the "time-boxed unit" within Scrum.
So, you can see that all three terms are related. I mostly engage with the sprint portion.
But not all Agile teams use sprints. Some use Kanban instead, which focuses on a continuous flow that is free from the "time-boxed unit". If you're in a sprint that uses a Kanban board, the concepts are being confused a bit.
Most teams use 2-week sprints. Once a sprint length is chosen, it should generally remain consistent. Holidays and various delays or what-have-you can push dates around though.
If a team fully integrates the Scrum framework, they can develop a sprint goal - that is, a single objective that provides focus for the sprint and informs decisions throughout the duration of the sprint.
The "definition of done" is a standard that defines what "done" means for work items of all kinds (e.g., coding, documenting, testing, reviewing, deploying). Without a clear "definition of done", team members may go out of sync with each other and work too little or not enough. That's why establishing a standard can help with consistency.
I can confirm these things exist. They were all a part of the structured team I mentioned above.
I saw a chart called a "Sprint Burndown Chart". The line for hours worked goes up and the line for hours assigned goes down. The two lines are supposed to intersect in the middle of the sprint. If you add scope, it pushes back the location of the lines intersecting and leads to a higher percentage of overflow into the next sprint. This is a tool to prescribe problems with work. Adding scope is something to be very careful about, especially for a "Firm Fixed Price" contract. So it helps to get the customer involved in the event of the team seriously needing to add scope.
I use Atlassian's Jira. Other tools include Azure DevOps, ClickUp, Linear, and physical Scrum boards.
There are a few important rules:
I have seen AI in professional work before. Obvious indicators include bullet points that start with emojis and the sentence framework, "it's not just X, it's Y" or "not with X, but with Y". Apparently em dashes are another tell presumably because it's a special character that word processors don't default to when you're typing.
Let's look at Slack's API documentation and reference it against these API documentation principles:
First, notice the layout of the webpage. The header has 4 tabs: Guides, References, Samples, Tools. The left and right sidebars work together for navigation: the left side navigates to new topics, and the right side navigates to sub-headers within the active topic.
Next, notice the prevalence of hyperlinks.
Let's look at the first guide.
From the left sidebar, select AI features for apps.
Here, the body content does not immediately show all the related code to the reader. It begins with general information. Beginners can read this to learn about the use case, while advanced users can scroll down find the task-oriented guides, which are accessed via hyperlinks.
Hyperlinks direct the user from the use case summaries to the code samples. This is
one of the biggest reasons most developers strongly prefer web-based API documentation over
printed books. Excluding the navigation, I counted more than 25 hyperlinks just
from this single
topic. The "Next steps" section at the bottom helps to guide readers who didn't click on any of
the previous hyperlinks. It offers five (5) different choices, each starting with a present
tense verb.
The left and right sidebars support navigation, and the
hyperlinks support discoverability.
The first thing the reader sees when they open the web page is a note that says "More doing, less reading" and invites the reader to immediately visit the Quickstart section. You can tell the intent is task-oriented. I would say this Quickstart section qualifies as the first guide, and I recommend including one just like it.
Looking at the Quickstart guide, the first thing I notice is the Python and JavaScript toggle. Fitting both processes into a single webpage with this toggle is intuitive and keeps the task contained within one topic instead of breaking it into two confusingly similar topics. When I say "task-oriented" that's a product of the intent behind this method of organization. Ideally, you want one topic per task, even when there is more than one way. Toggles are a great fit.
The code snippet boxes below have their own toggles as well. The choices are: Slack CLI and Browser. Making a selection in one code snippet box does the same for all the other boxes of its kind. Like the other toggle, this one too helps to keep the instructions task-oriented for similar reasons.
Let's also look at a more typical topic. Navigate to Guides > App management > Creating an app from the app settings. (Their procedure title naming convention is different from what I recommend, but we'll look past that for now.)
Aside from the prevalence of hyperlinks and code snippets, there is another feature that I like. Yes, there are color-coded CSS styles for various code elements. A scope is yellow, a method is green, and an event is magenta. (They call conversations.join a scope, which seems to be a mistake. The color coding is still a great idea.) Furthermore, the reader can click on the color-coded parts to navigate to the scope/method/event page on the References tab. It supports navigation and discoverability by offering hyperlinks within the context of the guide, but still stays task oriented by showing restraint from explaining the code's inner workings exhaustively here. Keeping the guides separate from the references is itself a way to make the guides more task-oriented.
As for the numbered procedural steps, refer back to the previous material in this tech writing course. API procedures are otherwise the same as any other software procedures.
Let's take a look at the structure carefully.
The first page provides three (3) buttons: Browse methods, Browse events, and Browse scopes. Each button leads to a huge index with a search function.
Next, navigate back to the References page, then from the left sidebar, expand Block Kit > Blocks.
The Blocks topic provides general information at the top followed by a table with search functionality. The table columns are: Name, Description, and Surfaces. There are no left, right, top, or bottom borders - only a horizontal line between the table rows. The table's background color matches the background color of the div behind it. This is a very open design and it works because there is no other content below to confuse it with.
The Actions Block topic is noticeably different. Now, the tables have a different background color or full borders - because there is more content below them. The References section continues to follow this style consistently for other topics: the parent topics are open, and their child topics are closed.
The tables in the child topics are: Facts and Fields. These are followed by code snippet boxes with toggles for different coding languages. Lines of code even appear to be color-coded inside the code snippets, and below, the page offers a hyperlink to the block kit builder, when applicable. External tools like that are optional but helpful extensions for API references. At the very least, I do recommend always including one or two examples here below the tables.
Navigate to the Samples page.
By default, the filters show all project types and all languages. The reader can select filters to narrow their search for a sample.
Each sample has an icon identifying its coding language alongside the title and brief description.
Some samples have a Tutorial button. This button links directly to the corresponding Tools page. In this way, the Samples page functions as a navigation hub for the Tools page; the samples are not actually located here. I actually recommend this over cramming the entire catalog of tutorials into the list of samples.
Some samples have a Code button. This button links directly to the corresponding GitHub page, which offers a separate space for setup instructions in the README panel. The reader can download code from here. While the GitHub page (or other code repository) is a totally separate interface from your API documentation, it's nonetheless important to provide a direct link.
The Tools topics are structured in much the same way as the Guides topics. The difference is that guides are high-level procedures for workflows, whereas tools are low-level procedures for executing specific tasks related to the tools. If your code takes on a form other than "tools", consider using a more accurate name for your use case, of course.
The hyperlinks here in the Community-developed tools topic link directly to Github too.
Oddly, some of the left sidebar selections (like Deno Slack SDK and Slack CLI) completely link away to separate sets of TOCs that don't have their own tabs. They have References pages of their own, seemingly separate from the website's References tab, which is somewhat muddy but it's a symptom of huge scope. I would recommend bringing all the major SDKs under the same header/navigation system or at least adding an SDK drop-down to the Tools tab.
///