user101040: This answer, explains what are SERIALIZE_METHODS and DESERIALIZE_METHODS macros in the Bitcoin Core. They prevent duplicate code for implementing the serialization and deserialization logic. But I've seen some classes in the Bitcoin Core which do the serialization differently. Here's an example:
/**
 * A UTXO entry.
 *
 * Serialized format:
 * - VARINT((coinbase ? 1 : 0) | (height << 1))
 * - the non-spent CTxOut (via TxOutCompression)
 */
class Coin
{

    ...

    template<typename Stream>
    void Serialize(Stream &s) const {
        assert(!IsSpent());
        uint32_t code = nHeight * uint32_t{2} + fCoinBase;
        ::Serialize(s, VARINT(code));
        ::Serialize(s, Using<TxOutCompression>(out));
    }

    template<typename Stream>
    void Unserialize(Stream &s) {
        uint32_t code = 0;
        ::Unserialize(s, VARINT(code));
        nHeight = code >> 1;
        fCoinBase = code & 1;
        ::Unserialize(s, Using<TxOutCompression>(out));
    }

So, what's the difference between these two way of implementing serializing and deserializing methods?

user208: Nothing.
The SERIALIZE_METHODS approach lets one write the serialization and deserialization code at once, but it effectively is just a (possibly) simplified way of writing the Serialize and Unserialize functions.
In this example, the author of the code just chose to write those functions directly and separately.

101040: <p>This <a href="https://bitcoin.stackexchange.com/a/114357/101040">answer</a>, explains what are <code>SERIALIZE_METHODS</code> and <code>DESERIALIZE_METHODS</code> macros in the Bitcoin Core. They prevent duplicate code for implementing the serialization and deserialization logic. But I've seen some classes in the Bitcoin Core which do the serialization differently. <a href="https://github.com/bitcoin/bitcoin/blob/v24.0/src/coins.h#L60" rel="nofollow noreferrer">Here's</a> an example:</p>
<pre><code>/**
 * A UTXO entry.
 *
 * Serialized format:
 * - VARINT((coinbase ? 1 : 0) | (height &lt;&lt; 1))
 * - the non-spent CTxOut (via TxOutCompression)
 */
class Coin
{

    ...

    template&lt;typename Stream&gt;
    void Serialize(Stream &amp;s) const {
        assert(!IsSpent());
        uint32_t code = nHeight * uint32_t{2} + fCoinBase;
        ::Serialize(s, VARINT(code));
        ::Serialize(s, Using&lt;TxOutCompression&gt;(out));
    }

    template&lt;typename Stream&gt;
    void Unserialize(Stream &amp;s) {
        uint32_t code = 0;
        ::Unserialize(s, VARINT(code));
        nHeight = code &gt;&gt; 1;
        fCoinBase = code &amp; 1;
        ::Unserialize(s, Using&lt;TxOutCompression&gt;(out));
    }
</code></pre>
<p>So, what's the difference between these two way of implementing serializing and deserializing methods?</p>
 208: <p>Nothing.</p>
<p>The <code>SERIALIZE_METHODS</code> approach lets one write the serialization and deserialization code at once, but it effectively is just a (possibly) simplified way of writing the <code>Serialize</code> and <code>Unserialize</code> functions.</p>
<p>In this example, the author of the code just chose to write those functions directly and separately.</p>
