"Reusing" 10 lines of code from a 100kb library is also a bad idea, unless you're absolutely certain that library would have been loaded anyway.

Features:

Adding stuff people need is generally a good idea (duh).

Adding things a single person requires is bad, unless you're sure the general users of your addon will embrace the new feature.

If your addon is popular enough, failure to follow rule 2 will eventually result in the creation of a competitor addon to your own.

Interface:

Slash commands are mostly evil. With the advent of load on demand, performance considerations isn't really an argument against them. Your user has a mouse.

Slash command are great for the following areas: scripting, macros, and commonly used commands.

The UI for an addon should be obvious to most people. It shouldn't take an hour to say, figure out how to open the options menu. (This doesn't count for people who don't read :))

Don't give the user too many options at once. Giant menus can freak people out just as much as a long list of slash commands.

Per Apple, encourage the user to discover new features

Performance:

How well an addon should perform is based on what it should do. Action bars should focus quite heavily on performance, while an option menu shouldn't.

Features that will significantly degrade the performance of a given addon should be completely separate from that addon, unless rewriting the addon to include those features will not decrease performance.

string.find and string.sub are slow.

Optimize areas that are executed a lot (duh).

Libraries
Libraries, even more so than addons, need to have very specific design goals.

Critiques of Other Addons, and Other Stuff

CT Raid
CT Raid performs poorly. This is a result of poor design (remember when CT Raid and Boss mods were one?), a lack of updates to take into account API additions, and also the decision to retain compatibility with older versions of CT Raid. The only real solution is to rewrite CT Raid, breaking compatibility with older versions like Apple did with OSX.

They're working on CT Raid 2, as a complete rewrite. This should be good news, as long as its written in a modular fashion. oRA is a good idea, but CT has the network effect to its advantage.

Ace Fallacy
The usual argument is, "I replaced this group of addons with Ace'd versions, and I gained x memory!" This was NOT due to Ace. Instead, it is due to either the replacement addons being better coded, or the replacement addons having a more narrow set of features (less bloat). The best Ace can help with is code reuse, but it comes at the cost of extra overhead.

Ace2

Ace2 is bloated. An Ace3 (Ac3?) should be written to "trim out the fat", that is reduce the entire thing to just core functionality.

The greatest strength and weakness of Ace is its community. Pitbull is a very good example of this. It started out as a "lightweight" unit frame addon, and features were rapidly added to it by the community. What has resulted is, however, quite bloated.

Ideally, Ace2 needs to become a series of downloads with a package management system, like APT. This would result in a system where the user maintains only a minimal set of libraries, with no copies, but also would require a large amount of work. WAU has helped this happen to a certain extent, but the transition is not complete

Event Handlers
A single event handler has one advantage over the "normal" way of creating event handlers for each frame: custom events. I have not done any large scale testing using a single event handler for all frames, but I would suspect that it would be marginally slower.

Code:

local f = CreateFrame("Frame")
f:SetScript("OnEvent", function(self, event, ...)
self:Call(event, ...)
end)
function f:Call(event, ...)
if self[event] then
for _, action in pairs(self[event]) do
action(event, ...)
end
end
end
function f:Add(event, action)
if not self[event] then
self[event] = {action}
else
table.insert(self[event], action)
end
end
function f:Remove(event, action)
if self[event] then
for i in self[event] do
if self[event][i] == action then
self[event][i] = nil
end
end
end
end

(It turns out this became the basis of BScript, which became BEvent/BVent)