You've gotten the most important advice so far:
• Document everything -- not the what but the why: Don't just say, "stop the motor when X happens"; I can read the code to see that that is happening. But why is X such an thing that the the pump should stop? That I don't know.
• Learn the process. Like they said, you can't control what you don't understand.
• Talk to the operators. What they need to do their jobs is not necessarily what you think they need. Operators tend to park on a single graphic where they can see the important stuff. Keep in mind that they might not know what is possible to do, and so may not ask for something they'd like.
• Keep in mind the guy who will inherit your work (which may be you, long after you've forgotten everything about it). Make it easy to follow and to troubleshoot.
More good practices:
• Bits are cheap; don't be afraid to add more, rather than making a single bit do too much, especially when things it does are similar, but not identical.
• On the other hand, don't overcomplicate your code either. If you have a rung that is merely a contact-to-coil { --| |------( ) }, you'd better have a good reason for the extra bit.
• Future proof as much as possible. Make array sizes bigger than you need them to be now. Because if the line is a success, they'll likely expand it. And it can be painful to increase memory allotment when you need it.
• Modularize your code. Device logic (valves, motors, input signals) can be little chunks of stand-along code. Each then can then be mapped to the physical I/O in simple I/O mapping logic (which would be lots contact-to-coil rungs that I warned against above; but with the justification that the internal logic uses the device objects, making it quick and easy to re-map the I/O should a card break). Similarly, your sequence logic can be split into "Actions" (mapping commands to the Device layer) and "Transitions" (what advances your sequence from one step/state to another).
• It's one thing to be able to program a sequencer to make things work the way they're intended when all goes right. Consider that as much as half your code could/should be dedicated to getting the system either back on track or to a safe landing when things go awry.
• Your GUI is as important as your control code. How you present what's happening is just as important as making everything work. If the operator doesn't know what's happening, they won't trust the system, and will likely not use it to it's full potential. Again this goes back to forming a partnership with the operators.
And last, but first:
• Make the system safe.