The Problem Decomposition of programs in terms of classes and in terms of crosscutting concerns are both useful, but languages based on source files allow only a single decomposition. A Solution Use a tool that lets developers create virtual source files (VSFs) by gathering together declarations from multiple classes. Virtual source files are effective views in that editing them results in corresponding changes being made to the original source code. VSFs let developers edit cross- sections of their code while maintaining its full object- oriented structure and without the need for additional language features. Programming With Crosscutting Effective Views Doug Janzen Kris De Volder Software Practices Lab Department of Computer Science University of British Columbia Vancouver, BC Canada Define a Set of Program Elements 1 The user creates a set of element identifiers called the Input Set by: Using comment tags, or Selecting elements from a browser, or Writing a query Render VSF 2 The tool creates a virtual source file by retrieving the source code for every element in the Input Set. Special syntax is used to identify which source file each block of text belongs to. Edit VSF 3 The user can add, change, and delete elements in the virtual source file. Parse VSF 4 The tool parses the virtual source file to produce the Output Set. Unlike normal source files, VSFs must be parseable in order to be saved. Update Source Files 5 The tool analyzes the differences between the Input Set I and the Output Set O to determine how the source files should be modified: Added elements:A = O – I Removed elements:R = I – O Same elements:S = I O class framework/Figure { drawing */ protected Graphics g; drawing */ public void draw() { … } class figures/Circle { drawing */ public void draw() { … } class figures/Square { drawing */ public void draw() { … } class framework/Figure { drawing */ protected Graphics g; drawing */ public void draw() { … } class figures/Circle { drawing */ public void draw() { … } class figures/Square { drawing */ public void draw() { … } package figures; class Circle extends Figure{ public int radius; drawing */ public void draw() { … } package figures; class Circle extends Figure{ public int radius; drawing */ public void draw() { … } package figures; class Square extends Figure { private int size; drawing */ public void draw() { … } package figures; class Square extends Figure { private int size; drawing */ public void draw() { … } package framework; abstract class Figure { drawing */ protected Graphics g; drawing */ public abstract void draw(); } package framework; abstract class Figure { drawing */ protected Graphics g; drawing */ public abstract void draw(); } framework/Figure>draw() figures/Circle>draw() figures/Square>draw() framework/Figure>g framework/Figure>draw(Graphics) figures/Circle>draw(Graphics) figures/Square>draw(Graphics) class framework/Figure { drawing */ protected Graphics g; drawing */ public void draw(Graphics g) { … } class figures/Circle { drawing */ public void draw(Graphics g) { … } class figures/Square { drawing */ public void draw(Graphics g) { … } class framework/Figure { drawing */ protected Graphics g; drawing */ public void draw(Graphics g) { … } class figures/Circle { drawing */ public void draw(Graphics g) { … } class figures/Square { drawing */ public void draw(Graphics g) { … }