teaching programming by teaching principles of reusability

7
Teaching programming by teaching principles of reusability 1 Robert Biddle*, Ewan Tempero School of Mathematical and Computing Sciences, Victoria University of Wellington, Wellington, New Zealand Abstract Teaching how to program is difficult, but we believe it can be made easier by concentrating on principles of software reusability. Our teaching strategy is based on a conceptual model of reusability that explains how features of programming languages support the creation of reusable software. The strategy has several advantages because it promotes a deep but practical understanding, and allows objective comparison and assessment. This paper outlines our approach in detail, and discusses our experience. q 1998 Elsevier Science B.V. Keywords: Teaching programming; Reusable software; Models 1. Introduction Learning how to program is difficult because it involves understanding a wide range of concepts. We believe a particularly effective teaching strategy is to explain the con- cepts of programming using principles that improve some characteristic of the software. This approach helps students better understand the concepts, and also emphasises the importance of producing software of good quality. The specific characteristic we have been concentrating on is soft- ware reusability. We have found that reusability provides a coherent and consistent explanation for all the programming concepts typically taught to beginners. In this paper, we outline a set of principles underlying software reusability and explain how these principles can be used to teach beginners about programming language features, and how they support successful software development. A focus on principles has important advantages over approaches based on specific techniques. Students who develop an understanding of principles will then be able to understand why and how the specific techniques work, and be well placed to understand new techniques when they encounter them. Principles are also language independent, so students can more rapidly learn new programming lan- guages. Moreover, an understanding of principles allows various specific techniques to be assessed and compared in an objective way. Our concentration on software reusability stems from our research work, which has involved developing a conceptual model of programming language support for reusability [1]. While we originally intended this model to facilitate research on programming language issues in software re- usability, we found it also provided principles extremely useful in our teaching. Further, it has been observed that software development is usually taught with an emphasis on software production from scratch, and little mention of the impor- tance of software reuse [2]. We believe our approach provides a good basis for improving this situation. This paper outlines our principles for reusability, explains how they can be used to explain a variety of issues about programming language features and how they support success- ful software design, and discusses our experience. Section 2 introduces the principles that form both the conceptual foun- dation for our views, and the basis of our exposition to students. Section 3 shows how we use these principles to explain the pivotal concepts of modern programming in terms of software reusability. In Section 4 we discuss our experience in using this approach so far. Finally, in Section 5 we present our conclusions. 2. A model for understanding reusability Software reuse concerns both the past, development with reuse, and the future, development for reuse. Development with reuse involves using already existing code in a new situation. Such code reuse has been carried out since the dawn of programming through the use of some form of cut-and-paste operation. While this is reusing code, it is 0950-5849/98/$19.00 q 1998 Elsevier Science B.V. All rights reserved PII S0950-5849(98)00040-8 * Corresponding author. 1 Parts of this paper have been presented at the Reuse’96: An Integral Part of Software Engineering workshop, Morgantown, West Virginia, USA, August 1996 and the Fourth International Workshop on Software Engineer- ing Education, Boston, Massachusetts, USA, May 1997. Information and Software Technology 40 (1998) 203–209 INFSOF 3898

Upload: robert-biddle

Post on 05-Jul-2016

224 views

Category:

Documents


4 download

TRANSCRIPT

Teaching programming by teaching principles of reusability1

Robert Biddle*, Ewan Tempero

School of Mathematical and Computing Sciences, Victoria University of Wellington, Wellington, New Zealand

Abstract

Teaching how to program is difficult, but we believe it can be made easier by concentrating on principles of software reusability. Ourteaching strategy is based on a conceptual model of reusability that explains how features of programming languages support the creation ofreusable software. The strategy has several advantages because it promotes a deep but practical understanding, and allows objectivecomparison and assessment. This paper outlines our approach in detail, and discusses our experience.q 1998 Elsevier Science B.V.

Keywords:Teaching programming; Reusable software; Models

1. Introduction

Learning how to program is difficult because it involvesunderstanding a wide range of concepts. We believe aparticularly effective teaching strategy is to explain the con-cepts of programming using principles that improve somecharacteristic of the software. This approach helps studentsbetter understand the concepts, and also emphasisesthe importance of producing software of good quality. Thespecific characteristic we have been concentrating on issoft-ware reusability. We have found that reusability provides acoherent and consistent explanation for all the programmingconcepts typically taught to beginners.

In this paper, we outline a set of principles underlyingsoftware reusability and explain how these principles can beused to teach beginners about programming language features,and how they support successful software development.

A focus on principles has important advantages overapproaches based on specific techniques. Students whodevelop an understanding of principles will then be ableto understand why and how the specific techniques work,and be well placed to understand new techniques when theyencounter them. Principles are also language independent,so students can more rapidly learn new programming lan-guages. Moreover, an understanding of principles allowsvarious specific techniques to be assessed and comparedin an objective way.

Our concentration on software reusability stems from ourresearch work, which has involved developing a conceptualmodel of programming language support for reusability [1].While we originally intended this model to facilitateresearch on programming language issues in software re-usability, we found it also provided principles extremely usefulin our teaching. Further, it has been observed that softwaredevelopment is usually taught with an emphasis on softwareproduction from scratch, and little mention of the impor-tance of software reuse [2]. We believe our approachprovides a good basis for improving this situation.

This paper outlines our principles for reusability, explainshow they can be used to explain a variety of issues aboutprogramming language features and how they support success-ful software design, and discusses our experience. Section 2introduces the principles that form both the conceptual foun-dation for our views, and the basis of our exposition tostudents. Section 3 shows how we use these principlesto explain the pivotal concepts of modern programming interms of software reusability. In Section 4 we discuss ourexperience in using this approach so far. Finally, in Section5 we present our conclusions.

2. A model for understanding reusability

Software reuse concerns both the past, developmentwithreuse, and the future, developmentfor reuse. Developmentwith reuse involves using already existing code in a newsituation. Such code reuse has been carried out since thedawn of programming through the use of some form ofcut-and-paste operation. While this is reusing code, it is

0950-5849/98/$19.00q 1998 Elsevier Science B.V. All rights reservedPII S0950-5849(98)00040-8

* Corresponding author.1 Parts of this paper have been presented at the Reuse’96: An Integral Part

of Software Engineering workshop, Morgantown, West Virginia, USA,August 1996 and the Fourth International Workshop on Software Engineer-ing Education, Boston, Massachusetts, USA, May 1997.

Information and Software Technology 40 (1998) 203–209

INFSOF 3898

ad hoc in nature. This means it cannot be systematicallyapplied in new situations and so cannot provide manybenefits. The benefits we expect fromreusablecode include:

• new applications can be built faster, because code does nothave to be reinvented (and rewritten and redebugged);

• applications are cheaper to maintain, because compo-nents can be improved and the benefits recouped by allapplications that use them; and

• applications are easier to understand because they arebuilt using well-known components.

We cannot achieve these benefits unless we can reusecode without some form of cut-and-paste, but quite oftenthe code we want to reuse does not quite have the function-ality we need for the new situation. In such cases, the codemust be written with the intention that it will be reused, thatis, it must be developedfor reuse. Our research work hasfocussed on developmentfor reuse, and has involved devel-oping a conceptual model of programming language supportfor reusability.

Our model is based of units of reuse, which we callassemblies. An assembly is anything that may ultimatelybecome valid source code. This includes simple entitiessuch as functions, classes, or modules, but also more com-plex entities such as all public methods of a class, or parts ofa macro definition.

To get the benefits listed above, we need the kind of codearrangements depicted by the ‘jigsaw’ diagram in Fig. 1. Onthe left of the figure, two assemblies are related in that atsome place or places one uses orinvokesthe other. Theshapes of the tabs and slots show which assemblies maybe used together. The effect is as if the second assemblyhas somehow been inserted into the first assembly. In suchsituations, we call the invoking assembly thecontextand theinvoked assembly thecomponent. Each different contextthat invokes a component represents a use or reuse of thecomponent. This structure reflects well-known program-ming language mechanisms such as macro definition andexpansion, and procedure definition and call. It also appliesto more recent concepts, such as the definition and instantia-tion of classes in object-oriented programming.

An important aspect of this structure is that it also worksin reverse. The common case iscomponent reuseasdescribed on the left of Fig. 1. Sometimes, however, wework the other way around: we have a context, and use itwith different components, as shown on the right of the

figure. For example, we might have context code that callsa procedure, and in a different setting we may need the samecontext code, but want a different procedure to be called.We call thiscontext reuse.

The main goal of developing our model is to understandwhat features of an assembly improve or reduce the like-lihood that assembly will be reused, that is, what featuresimprove or reduce the assembly’s reusability. Context andcomponent are reallyroles played by assemblies. As thefigure shows, an assembly can play both roles. This obser-vation, together with the notion of context reuse, shows thatany discussion of reusability must encompass both compo-nent and context.

When considering the reusability of an assembly, thereare two aspects of the assembly that are relevant. One iswhether or not the assembly is likely to be used again, its‘usefulness’. The other is whether or not there are aspects ofits implementation that would prevent it from being usedagain, its ‘ease of use’. Ease of use depends on the expecta-tions the context and component have of each other, whichwe calldependencies.

Dependencies can adversely affect the reusability of anassembly, because they limit the number of contexts thancan invoke it, or the number of assemblies it can invoke.Nevertheless, there are dependencies that are beneficial toreusability, allowing customisability and checkability.

Customisability. The customisability of a component isthe amount of control a context has over how the con-text dependencies are met. The customisability of acontext is similar. For example, parameters providedifferent ways for the caller of a function to dictatehow the function behaves to meet the caller’s require-ments.Checkability. The checkability of a dependency is thedegree to which it can be checked that the dependencyhas been met. The requirement that the parameters to aprocedure be a certain type is a dependency. Somelanguages do not check that the types of the actualparameters are correct at all, some check only at run-time, while others check at compile-time.

We have also found it useful to classify dependenciesaccording to the support provided by the software develop-ment environment.

Explicit. An explicit dependency is one that can bedescribed by constructs in the programming language.For example, the import clause in Java indicates whatother packages the class being implemented dependson.Implicit. An implicit dependency is one that cannot bedescribed by constructs in the language, but whether ithas been met can be automatically checked by theenvironment (such as the compiler, linker, or loader).For example, the Cþþ template implementation maydepend on one of the argument types having a specific

Fig. 1. Jigsaw diagram showing both component reuse and context reuse.

204 R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209

function (such as print). There is no language supportfor making this dependency explicit, but it will bedetermined at link time whether or not this dependencyhas been met.Informal. An informal dependency is one that cannot bedescribed by constructs in the language, and nor can itbe easily checked. For example, a list implementationmay be expected to maintain items in order. Any clientof the implementation will depend on these semanticsbeing met, however in most traditional languages thiscannot be checked. This is changing as more languagesinclude constructs for specifications.

Table 1 summarises our model. More details can be foundelsewhere [1,3].

3. Teaching with the reusability model

In this section, we explain how our model can be used tofocus on reusability while teaching how to program. It is ourintention that this approach not only emphasises the impor-tance of reusability, but also motivates a deeper understandingof the program design process, and how programminglanguages support this process.

Although we believe the principles we discuss are valid ingeneral, we acknowledge that many of the points we makearise from consideration especially of the imperativeprogramming paradigm, and those languages we haveused in our teaching: Pascal, Modula-2, C, Cþþ, andJava.

3.1. Procedures: component and context reuse

We assume here that students understand the primitiveelements of programming such as variables, expressions,statements, sequences, selection and iteration. At thispoint, any non-trivial program built using only theseelements will quickly involve repeated programming,debugging and so on. It is then very easy to motivate re-usability as an important issue.

We present procedures as a way to allow an assembly ofexecutable statements to be written in one place, andinvoked from many others. Interestingly, this most basicreality of procedures has in recent years sometimes beenmissed by beginners because of the emphasis on the roleof procedures in top-down design.

This use of procedures emphasises component reusabil-ity. Our model suggests that to increase reusability weshould be careful to avoid dependencies the componenthas on the context, so that the component can be invokedby different contexts. In practical terms, this motivatesdiscussion of procedures using global variables from thecontext, and how this limits component reusability.

The symmetry of our model means we should also con-sider context reuse. Procedures can call other procedures,and so can be contexts as well as components. Context reusewith regard to new procedures involves new proceduresbeing created to match existing calls. This motivates theconcepts of separate compilation and procedure libraries,both of which support context reuse.

Consideration of context reuse should also include theimportance of avoiding dependencies the context has onthe component, so that the context can invoke differentcomponents. In practical terms, this motivates discussionof scope that disallows contexts from using names fromwithin procedures, thus supporting context reuse.

In our model, we suggest that many dependencies aredetrimental to reusability, but describe two cases wherethey are beneficial: for customisability, and for checkability.

3.2. Procedures: customisability

In explaining the role of procedures in both componentand context reuse, the issue of customisation quicklybecomes evident. While procedures appear to solve the pro-blem of avoiding repeated work, beginners quickly learnthat they seldom want to reuseexactlythe same proceduresin different contexts, but that procedures need to be some-how tailored to fit new situations.

Global variables provide a good starting point for discuss-ing customisability of procedures. While they createinappropriate dependencies on the context, theycan beused to customise procedures. It is useful to demonstratethis to show how dependences can affect reusability,since, while customisation is possible this way, global vari-ables are not ideally suited to the task. Firstly, uses of globalvariables areimplicit dependencies, and this is a drawbackfor reusability because programmers will find it difficult todetermine what a context must provide in order to reuse theprocedure. Secondly, uses of global variables are dependen-cies onnames, which are in fact irrelevant to the procedure’sbehaviour. This is drawback for reusability because reuse isonly safe where names inside and outside the procedure donot clash—something that is difficult to plan for.

Thus, parameters can be introduced as support for custo-misation that addresses both of the weaknesses involved inusing global variables for customisation. Where a contextuses parameters instead of global variables, the dependen-cies are explicit, instead of implicit. Accordingly, aprogrammer can easily see what a context must provide inorder to reuse the procedure. Moreover, now the componentdepends on the context to supply avalue to the parameter,

Table 1Model summary

Dependency between ContextComponent

Beneficial effect on reusability CheckabilityCustomisability

Language support for dependency ExplicitImplicitInformal

205R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209

and external names are properly irrelevant. Finally, we candistinguish between pass-by-value and pass-by-reference asdeciding whether the value dependency is only by theprocedure on its caller, or both ways.

3.3. Procedures: checkability

Our model emphasises reusing components in differentcontexts, and contexts with different components, butacknowledges that there is a need to ensure the integrityof any invocation. Especially with experience of parameters,students appreciate that the whole approach only works prop-erly when contexts invoke the components they intend to, andwhere dependencies are indeed met. This motivates the needfor dependencies to better provide checkability.

Checkability is supported by procedures by matching thename from a call to a procedure heading. But, the reallyimportant dependence of a context on a component is infor-mal dependence on semantic matters, and this is difficult tocheck. The name of the procedure can be used to indicate itssemantics, thus the introduced dependency on the name is asimplification that improves checkability.

In practice, checkability becomes more of an issue whereprocedures have parameters, since this requires the matchingof actual and formal parameters. We can use this opportunityto introduce the role of type systems. We explained para-meters as dependencies involving values, but checkabilityof values is likely to be informal and involve run-timechecking at best. We can address this by introducing depen-dencies on the types of parameters: this is less detrimental toreusability than dependence on names, but more checkablethan dependence on values.

3.4. Defined types: component and context reuse

Procedures represent executable statements, but that isnot the only kind of code we might want to reuse—wemay also want to reuse data declarations, or user defineddata types.

Data type declarations allow a programmer to describe adata structure once, but use it to declare data as necessary.They are similar to procedures, in that they enable reuse ofdata declaration assemblies in a way similar to how proce-dures enable reuse of executable statement assemblies. Aswas the case with procedures, user defined types can alsouse other user defined types — this is sometimes calledcomposition. We emphasise composition because we havenoticed some beginners fail to appreciate its importance.

As with procedures, the symmetry of our model againsuggests we consider context reuse. In this case, contextreuse involves new data type declaration assemblies beingused with existing code that declares data to be of that type.

Dependencies can also affect the reusability of userdefined types. We have to consider dependencies a datadeclaration has on its context, and the dependencies a con-text has on it. This motivates a discussion on encapsulation,

abstract data types, and classes. Encapsulation limits whatcan access different parts of the user defined type. Withabstract data types and classes, encapsulation is used togroup data declarations with designated procedures, andallow only those procedures to access the internals of thedata declarations. This forces the context to use theseprocedures to work with values of the type. With suchprogramming language support, we make it clear howdependencies of the context on the component can beavoided or controlled, thus better promoting contextreusability. This is the basis for encapsulation in abstractdata types and, in object-oriented languages, classes.

3.5. User defined types: customisability

When becoming familiar with procedures, even begin-ners rapidly see the need for customisability. When becom-ing familiar with user defined types, the need does not seemso obvious so quickly. Nevertheless, there are two commonsituations that do motivate understanding of the need.

The first motivating situation concerns types that involvesome size, but where different contexts require a differentsize to be used. In some cases, the size is used at run-timeand can be provided by using parameters of interfaceprocedures, thereby accomplishing type customisabilityvia procedure customisability. But, in many compiled lan-guages, some sizes need to be known at compile-time, andthat strategy does not work. Another approach is to useglobal constants, but that has the drawbacks discussedwith regard to customising procedures using globalvariables. Moreover, it typically restricts types to beingcustomised in one way throughout a whole program.

The second motivating situation concerns ‘container’types, where the containing structure is significant, but thetype of the contained items is not. This need can again beaddressed by using global type names. For example, alisttype may depend on alist_item type for the items in thelist, but thelist_item type may be left to be defined bythe context. The drawbacks are the same as above: implicitdependence, dependence on names, and typically a limita-tion to one customisation per program.

With this motivation, we can parallel our presentation ofprocedures, and introduce parameterised types. By usingparameterised types (such as Cþþ template classes) wecan make it clear that the dependencies can be madeexplicit, and the dependencies can avoid involving typenames from the context. Moreover, because there is nodependence on context type names, this approach can beused to allow a number of different customisations of adata type in the same program.

3.6. User defined types: checkability

Checkability for user defined types appears similar tocheckability for procedures. With a simple user defineddata type, the name is an introduced dependency that stands

206 R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209

in for informal dependencies and promotes checkability.And with parameterised types, the need for matching con-text and component implies that dependencies on the type ofthe parameters would be beneficial in the same way as is thecase for parameterised procedures.

There is, however, one important difference from the caseof procedures. The introduction of encapsulation means thatchecking that the correct type is being reused need not meanmatching names. This is because encapsulated types areused via the procedures that are associated with them, sothis set of procedures (and their parameters) can be an alter-native way of type checking.

This observation raises the issue of what type checkingshould mean. While strict name matching between contextand component does support checkability, this checkabilitymay be stricter than necessary. For example, in the case ofclasses, what is important is that the supplied class has themethods being called on it. It is usually not necessary thatthe supplied class have a particular name. In other words,what we care about is checkinginterfaces, that is, the set ofprocedures and their argument types. With this as motiva-tion, we can introduce inheritance and polymorphism.

3.7. User defined types: inheritance and polymorphism

Inheritance and polymorphism are concepts from object-oriented languages that must be introduced with care.Widespread publicity about object-oriented programminghas resulted in many students being keen to use these tech-niques before they really understand them. We do believethat inheritance and polymorphism are best explained interms of reusability. Nevertheless, we feel the subject isbest left late in the teaching sequence, when studentsalready have a good understanding of both compositionand type checking.

Following from the earlier discussion of checkabilityabove, we can introduce inheritance by emphasising therole of interface conformance. One interface conforms toanother if it provides at least the same set of procedures thatare used in the same way as the other. Thus, when we use auser-defined type, what we check is that the interface of theuser-defined type conforms to the interface we need. Wedescribe inheritance as a way to specify when differentclasses conform to the same interface.

We can then explain how inheritance also works likecomposition, in that it allows the type to reuse the data

declarations and procedures of the base type. So, we doacknowledge that inheritance and composition are similarin this way, but we continue to emphasise that it is interfaceconformance that is the distinguishing characteristic ofinheritance.

Fig. 2 shows the jigsaw diagrams we use to make clear thedifference between inheritance and composition. An‘employee’ class can reuse an existing ‘address’ class bycomposition (top), but composition produces a differentinterface for employee than for address (see tabs on toppart of diagram). Nevertheless, a ‘manager’ class canreuse the existing employee class via inheritance, andhave an interface that conforms to the employee class inter-face (see tabs on bottom part of diagram).

Interface conformance increases reusability by allowingcontext code to invoke either the base class or a derivedclass. This is possible, because the interfaces of both classesconform to that of the base class, and so instances of thederived class may be used anywhere instances of the baseclass may be used. Thus, with inheritance, we can use acontext with several different component classes. This isthe primary connection between inheritance and reusability:inheritance supports context reusability.

Fig. 3 illustrates the connection between interfaceconformance and context code reusability. Because theinterface of the manager class conforms to that ofthe employee class, objects of the manager class can beused in place of objects of the employee class in the contextcode. Accordingly, context code, such as the code to printmailing labels, may have been created to work with objectsof the employee class, but may be reused without modifica-tion for objects of the manager class.

Typically, when different classes conform to the sameinterface, they behave differently. However, interface con-formance means they can be used by the same contextwithin a program. This is our explanation of polymorphism:where context code is used with different classes that con-form to one interface, but where each has differing behaviour.

Interface conformance also explains the role of the inter-face mechanism in Java. A Java interface is a set of methodsignatures, and it differs from a class in that it cannot haveany implementation associated with it. A class that supportsor implements a particular interface must explicitly statethat it does so. The advantage of an interface is that contextcode can be written in terms of it, and then used with anyclass that implements the interface. In this way, the context

Fig. 2. How interface conformance makes inheritance different thancomposition. Fig. 3. How interface conformance leads to reusability of context code.

207R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209

code will be reusable with any implementation of the class,even if several implementations are used within oneprogram.

4. Implications and experience

As mentioned in the introduction, our approach comesfrom our research. We developed our model to help usunderstand how language features affected reusability, butdiscovered that our model also helped us explain issues inprogramming more clearly. We are particularly pleasedwith how our model addresses three issues: inheritance,encapsulation, and type checking.

4.1. Learning about inheritance

The topic that initially focused our attention on reusabilitywas the widely acclaimed connection between object-oriented programming and code reuse (for examples, seeRefs [4,5]). We felt that although many learners appreciatedthe claims in theory, many had difficulty in designing pro-grams in practice. In particular, learners often had difficultyin understanding when to use inheritance, and even moredifficulty with multiple inheritance.

Many writers attempt to explain the role of inheritance byshowing examples of it being used in application domainsthat feature well-understood classification hierarchies (forexample, the ‘zoo animal’ examples of Lippman [6]). Stu-dents find this approach appealing, but quickly discover thatbuilding one’s own hierarchy in realistic programming situa-tions is much more difficult than these presentations suggest.

The usual advice about inheritance is to use it to representthe ‘is a’ relationship. While this advice is intuitively attrac-tive, imaginative students have no difficulty envisaging‘is a’ relationships between some very disparate classes!An advantage of our approach is that it replaces the sub-jective ‘is a’ test with the objective ‘conforms to’ test.While students must still calculate whether or not they aregetting any advantage from any conformance relationshipsthey create, they find this test easier to apply correctly astheir own biases are less likely to affect their decision.Moreover, it replaces the philosophical nature of ‘is a’with the very practical nature of ‘conforms to’, so makingsoftware reuse the important criterion. We discuss ourapproach to teaching inheritance via reusability in detailelsewhere [7].

4.2. Learning about encapsulation

Whereas we believed that inheritance was a concept thatneeded to be taught and learned better, we initially felt thetopic of encapsulation was typically well explained andunderstood. Nevertheless, we did feel that encapsulation,both of procedures and of data types, did play a significantrole in making code reusable, and so we addressed

encapsulation in our model. In doing so, we ourselves beganto better understand the role of encapsulation, even though wehad previously thought we understood it perfectly well.

We believe that traditional explanations of encapsulation,both of procedures and of classes, concentrate on the codethat is encapsulated, that is, the component. But, as we haveoutlined in the previous section, encapsulation typicallypromotes the reusability and reuse of thecontext code,not the component code. With our new approach toexplaining encapsulation, not only do we maintain a focuson reuse and reusability, we also feel we are giving morepractical and more specific advice about when and how touse it.

4.3. Learning about type checking

An issue related to encapsulation is that of type systemsand type safety. Again, this is something that we had not feltwas poorly understood, but we feel our new approach is animprovement. While students had previously understood theimportance of type safety as important for preservation ofintegrity, we suspect that they had too philosophical anapproach to understanding types.

For example, we recall many discussions with studentsconcerned as to whether a class was ‘really’ a stack, or a list,or map, or whatever. Our new approach to explaining typesconcentrates on their role in providing checkability betweencontext and component, so benefiting reusability and reuse.This has the result that students become less concerned withthe philosophical aspects of the nature of types, and moreconcerned with the engineering issues at hand.

4.4. Experience

Our experience in applying this approach is now morethan 5 years old, and includes teaching a university compu-ter science programming course to second year students,and short courses on object-oriented programming for pro-fessionals in industry. While we are suggesting that thisapproach is a way of making software reuse and reusabilitya central issue right from the start, so far we have only usedthe approach with students who have already learned someof the fundamentals of programming.

Although we have not used this approach with completebeginners, we believe that it would work well. Beginnerslearning practical programming are also learning a program-ming language, and this can result in beginners confusinggeneral principles with language peculiarities. Our approachaddresses this by making it clear that the language featuresare not themselves the principles, but represent attempts tosupport the principles. Accordingly, language details arejust superficial details. This keeps the students aware ofthe role of the language, and of its strengths and its limita-tions. We hope this will mean students will be better able tounderstand other languages later on, rather than being‘locked in’ to one way of programming.

208 R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209

5. Conclusion

We claim that reusability can be made a primary focuswhile teaching how to program. Our approach to doing thisinvolves an explicit model for how reusability is supported.Our model involves both contexts and components, and thedependencies between them. We concentrate particularly onhow some dependencies benefit reusability by supportingcustomisation and checkability, despite other dependenciesaffecting reusability adversely. With this small set of prin-ciples, we can explain key features of programminglanguages, from simpler features such as procedures, userdefined types, or scope, to more complex features such asencapsulation, inheritance and polymorphism. Our modelalso allows uniform treatment of diverse issues such aswhy global variables are problematic, why type checkingis important, and how separate compilation works.

We believe that there are several factors involved thatmake our approach worthwhile. Firstly, we thinkthat although many techniques and programming languagefeatures that support reusability have been developed overthe years, there is a need to further develop a principled wayof discussing the common goals and common themes invol-ving reusability. We intend our model to address this need.Secondly, we feel that many guidelines to beginning pro-grammers are too vague, and not sufficiently operationalenough to make it clear how programming goals canactually be achieved with the tools available. Thirdly, wehope that by explicitly recognising reusability as a key goalin program design and construction, we will influencebeginning programmers to keep focused on both reusabilityand reuse throughout their education and professional workin software engineering.

Finally, we hope that by focusing on reusability, we canbegin to address an issue that we believe arises in all

software engineering curricula—how to teach design skillsmore effectively. We advocate teaching design skills asearly as possible in the curriculum. However, we do notbelieve it is possible to effectively teach design beforestudents have a good understanding of the technology thatwill be used to implement the design, namely the program-ming language. Thus, the teaching of design cannot beginuntil the students have had a chance to gain experience withthe fundamentals of programming. We believe that byemphasising reusability when these fundamentals arebeing taught, we will provide a good foundation toeffectively teach design.

In conclusion, we believe that teaching of programmingand design should be based on sound principles that demon-strate practical benefits. We have found emphasisingprinciples of reusability to be particularly effective.

References

[1] R. Biddle, E. Tempero, Understanding the impact of language featureson reusability, in: M. Sitaraman (Ed.), Proceedings of the 4th Inter-national Conference on Software Reuse, IEEE Computer SocietyPress, April 1996.

[2] E. Yourdon, Decline and Fall of the American Programmer, YourdonPress, 1993.

[3] R. Biddle, E. Tempero, Modeling units of reusability. Technical ReportCS-TR-96/19, Victoria University of Wellington, November 1996.

[4] G. Fischer, Cognitive view of reuse and redesign, IEEE Software 4 (4)(1987) 60–72.

[5] B. Meyer, Reusability: the case for object-oriented design, IEEESoftware, March (1987) 50–64.

[6] S.B. Lippman, Cþþ Primer, 2nd ed., Addison-Wesley, Reading, MA,1991.

[7] R. Biddle, E. Tempero, Explaining inheritance: a code reusabilityperspective, in: Proceedings of the 27th ACM SIGCSE TechnicalSymposium, February 1996.

209R. Biddle, E. Tempero/Information and Software Technology 40 (1998) 203–209