01
Step one: define input and result
Start with the function signature and state exactly what it accepts. Suppose you document validateEmail(value), which takes a string and returns an object with a valid flag and a message. Say whether it trims spaces, whether empty strings fail and what happens with null. Show one passing and one failing call side by side, with the literal returned objects. Readers should be able to predict output without running anything. Avoid describing the rules in vague terms like 'checks the format'; name the specific conditions, such as requiring one at-sign and a dot in the domain part.
02
Step two: write messages people can act on
Error text is part of the interface, so document it as carefully as the logic. For the email example, 'Invalid input' tells a user nothing, while 'Add the part after the @ sign, like [email protected]' points to a fix. List each failure case with its message and the field state it should trigger. Note whether messages are fixed strings or can be overridden for other languages. Include a short table pairing input, result and message, because developers scan tables when debugging. Keep the wording neutral and brief so it fits beside any form layout without needing rewrites.
03
Step three: show integration and edge cases
Finish with a runnable snippet that connects the function to a form field, including when it fires, such as on blur or on submit. Then list edge cases honestly: leading spaces, uppercase letters, very long strings and addresses with plus signs. State which are accepted, which are rejected and why. Add a note that client-side checks improve usability but do not replace server-side validation. A final checklist of three or four items lets a reader confirm their setup works. This turns the page from a reference into something a developer can follow once and trust later.