When deciding between when to make use of assert versus require, one must consider two key factors in their deliberation: (1) gas efficiency and (2) bytecode analysis. The functions Assert() and Require() may be used to check specified conditions are met and consequently throw an exception in the event the condition is not met.
Assert() should only be used to test for internal errors, and to check invariants.
Require() should be used to ensure valid conditions are met that cannot be detected until execution time.
You may optionally provide a message for require, but not for assert.
Examples of internal errors include: dividing by zero, converting a oversized value, allocating too much memory, or accessing a storage byte array that is incorrectly encoded.
Examples of valid conditions include: message sender must be the owner, the balance of a user must be at least the deposited amount, or the allowance must be at least the amount being sent.
• assert(false) compiles to 0xfe, an invalid opcode, thus using up all remaining gas, this because the assert function creates an error type Panic(uint256).
• require(false) compiles to 0xfd, the revert opcode, thus refunding the remaining gas.
When used as intended, analysis tools may identify conditions wherein which function calls result in a failing assert, which should never be the case in properly-functioning code — if this happens there exists a bug.
• Validate User Inputs: such as require a user inputs a value above or below a specified amount or only for a certain asset.
• Validate State Conditions: prior to executing state changing operations, for example in an owned contract.
Require() is more commonly used than Assert(). In fact, I hardly ever use assert and when I do it is for good reason. Another thing to note is conventionally, require statements are used towards the beginning of a function.
• Checking for Overflow or Underflow: these are both arithmetic errors.
• Checking Invariants: cases where the anticipated change does not occur.
• Validating Contract State: ensuring anticipated state post-changes.
Unlike with Require(), you may expect to see Assert() towards the end of your function. In essence, assert is primarily there as a means to prevent anything really bad from happening.