Code smells are things like hard-coded values, duplicate code, and poorly chosen names. Code smells tend to affect readability and simplicity. Refactoring code smells usually involves renaming or extracting to methods.
Design smells, on the other hand, tend to be more subtle. They usually affect maintainability and flexibility although symptoms of a poor design can also include unclear or misleading code. Design smells usually involve a violation or violations of one or more design principles like SOLID, DRY, and GRASP.
I don't think there's a clear line of demarcation between the two though -- code smells can often be symptoms of deeper problems in the overall design.
Design smells are design aspects that violate fundamental design principles and violate design quality. Design smells are candidates for refactoring.
Bad smells are certain structures in code that indicate the violation of fundamental design principles and negatively impact software quality. When we analyzed smells, we realized that smells are at different levels of granularity and in the same way, refactorings have different scope (we have written it as an article here: http://www.designsmells.com/article.php?id=11). Here is relevant extract from that article:
* When a module is “excessively large”, it needs to be “broken-up” into smaller modules
* When a class is “excessively large”, it needs to be “broken-up” into smaller classes
* When a method is “excessively large”, it needs to be “broken-up” into smaller methods
In other words, smells can be viewed at different levels of granularity:
• Architecture smells: Examples include layering violations (there are accesses from a lower level to a higher level layer), tangled modules (two or more modules are tightly coupled because of two or more cycles between them), and large interfaces for components (the component exposes a large number of methods).
• Design smells: Examples include refused bequest (a method in a derived class rejects the method inherited from its base classes), classes with multiple responsibilities, and cyclically dependent classes.
• Implementation smells: Examples include loops that perform multiple tasks, large methods, and complex conditional statements.
Looking at smells based on the artifact granularity is useful in practice. When we talk about smells in sub-systems or modules, we are at a higher-level of abstraction, and hence dealing with architectural level concerns. When we are dealing with smells that relate at class-level abstractions (within a class but higher level than methods or relationship between classes), we are at the detailed design abstraction level. When we talk about implementation smells, we are dealing with concerns with localized impact such as complex conditionals within a method.