I'm not sure why inheritance was developed. I had thought it happened in Smalltalk between 1971 and 1976; in Smalltalk-76 http://worrydream.com/refs/Ingalls%20-%20The%20Smalltalk-76%... it's justified as follows: "This capability leads to a highly factored system." The first example given is that Window has subclasses such as a text editor for the source code of a class. (This was before per-method editing.) A later example is Number, which provides many comparisons such as ≤ and ≠ in terms of a smaller number of basic comparisons.

However, it turns out it was in SIMULA 67, taken from a 1965 proposal by Tony Hoare for record handling in Algol, which I haven't been able to find yet. That is, it was proposed in a context where objects had fields, but not methods, and thus not protocols either. SIMULA 67 had overriding of superclass methods if they were marked “virtual”, as in C++.

Turning back to Window and Number, an alternative using composition instead of inheritance puts the shared and unshared code in different objects. The Window class becomes one class only, with a field indicating what its contents are, to which it delegates paint messages and handling of input events; Number becomes a wrapper that expects its contents to implement < and ==, perhaps, and implements the other four methods on top of them.

How does this differ from the approach using inheritance? It's a great deal more hassle to change your mind about which methods are delegated to the wrapped object, but much easier to be sure that other refactorings are correct, because it's much easier to tell which methods could potentially be “overridden by a subclass”. It affords the possibility of changing the contents of a Window over time—particularly useful in languages like Python where reloading code after a modification creates new classes rather than modifying the existing ones. It costs an extra allocation and an extra method call on every delegated method (fatal in the case of SmallInteger, normally a subclass of Number, but SmallInteger is already a collection of hacks for efficiency; giving it an independent implementation of the Number protocol is reasonable).

Perhaps we should regard inheritance as an efficiency and convenience hack for cases where memory is tight or we're initially exploring an OO design, one we should remove later to improve maintainability once it's more or less clear how to divide up the responsibilities.

Smalltalk-80 used inheritance for its collections library, in a way that does not respect LSP, perhaps understandably because Barbara Liskov was on the other coast, and CLU was a very different language from Smalltalk. Some more recent languages like Java modeled their collections after Smalltalk’s. I don't think it's entirely fair to ding Josh Bloch for this.

Rigorously modeling inheritance (with overriding, open recursion, and covariant self type) turns out to be quite challenging; I recommend Abadí and Cardelli's A Theory of Objects to those who are interested.

The most interesting thing I'm looking at right now with regard to software design is Jackson's Alloy model checker, which does a kind of abstract-interpretation exhaustive test of your high-level design to verify that in examples to a certain size, your desired properties hold. This is of course a different level of abstraction from the factoring of the implementation to eliminate duplication, but it can tell you which contemplated protocols are fatally flawed.