Software-Projekt Prof. Dr. Rainer Koschke Fachbereich Mathematik und Informatik Arbeitsgruppe Softwaretechnik Universität Bremen Wintersemester 2006/07 Überblick I 1
1 Motivation Architekturkonformität Programmierrichtlinien Anhang Wiederholungsfragen Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 3 / 33 Lernziele Feinentwurf eines Systems durchführen können Programmierrichtlinien entwerfen, kennen und einhalten Verständnis für Codequalität entwickeln Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 4 / 33
Feinentwurf Der Feinentwurf ist die Brücke zwischen abstrakter Architektur und detailliertem Code. Er legt fest: Datenstrukturen Klassendiagramme mit zusätzlichen sdetails; (z.b. Navigierbarkeit, von Assoziationen, Behandlung von Mehrfachvererbung oder weiteren sklassen etc.) Abläufe Zustandsautomaten Aktivitätsdiagramme Sequenzdiagramme Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 5 / 33 Architekturkonformität Architekturbeschreibung und Quellcode sind zwei von einander abhängige, aber separate Dokumente in der Weiterentwicklung werden oft Änderungen im Quellcode gemacht, die in der Architekturbeschreibung nicht nachgezogen werden Folge: Architekturbeschreibung wird obsolet Planung erfolgt aber meist auf Basis der Architekturbeschreibung Folge: böses Erwachen in der Umsetzung Reflektionsmethode von Murphy u. a. (1995, 2001) zur Synchronisation von Modulsicht und Quellcode Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 6 / 33
Reflektionsmethode (Murphy u. a. 2001) 1 Stelle Architekturmodell auf 2 Extrahiere smodell 3 Bilde Modelle aufeinander ab 4 Berechne Reflektionsmodell 5 Verfeinere/korrigiere Beispiel H1 H2 H3 Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 7 / 33 Warum Programmierrichtlinien? bis zu 80% der Gesamtkosten für Software sind Wartungskosten Originalautor wartet Software oft nicht selbst Code muss lesbar und verständlich sein Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 9 / 33
Programmierrichtlinien: Schlechte Beispiele i n k o n s i s t e n t e Methodennamen T e x t F i e l d. s e t T e x t ( ) ; L a b e l. s e t T e x t ( ) ; Button. s e t L a b e l ( ) ; A b s t r a c t B u t t o n. s e t T e x t ( ) ; i n k o n s i s t e n t e P a r a m e t e r s o r t i e r u n g S t r i n g B u f f e r. setcharat ( i n t index, c h a r c ) ; Vector. s e t E l e m e n t A t ( Object o, i n t i n d e x ) ; L i s t. s e t ( i n t index, Object o ) ; l e n g t h oder s i z e? l e n O f A r r a y = myarray. l e n g t h ; l e n O f S t r i n g = mystring. l e n g t h ( ) ; mylist. s i z e ( ) ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 11 / 33 Programmierrichtlinien: Sinnvolle Namen S i n n l o s e Namen s t a t i c f i n a l i n t ONE = 1 ; s t a t i c f i n a l i n t TEN = 1 0 ; s t a t i c f i n a l i n t TWENTY = 3 0 ; b e s s e r s t a t i c f i n a l i n t INPUT MODE = 1 ; s t a t i c f i n a l i n t INPUT BUFSIZE = 1 0 ; s t a t i c f i n a l i n t OUTPUT BUFSIZE = 3 0 ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 12 / 33
Programmierrichtlinien: Lokale Variablen Man kann s auch ü b e r t r e i b e n... f o r ( i n t o u t e r I n d e x = 0 ; o u t e r I n d e x < maxouterindex ; o u t e r I n d e x++) f o r ( i n t i n n e r I n d e x = 0 ; i n n e r I n d e x < o u t e r I n d e x ; i n n e r I n d e x++) r e s u l t M a t r i x [ o u t e r I n d e x ] [ i n n e r I n d e x ] = o u t e r I n d e x i n n e r I n d e x ; S c h l e i f e n v a r i a b l e n / I n d i z e s => k u r z e Namen f o r ( i n t i = 0 ; i < max ; i ++) f o r ( i n t j = 0 ; j < i ; j ++) r e s u l t [ i ] [ j ] = i j ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 13 / 33 Ausdrücke in natürlicher Form schwer v e r s t ä n d l i c h e r Ausdruck i f (! ( b l o c k I d < a c t b l k s )! ( b l o c k I d >= u n b l o c k s ) ) b e s s e r i f ( ( b l o c k I d >= a c t b l k s ) ( b l o c k I d < u n b l o c k s ) ) Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 14 / 33
Magische Zahlen Wer v e r s t e h t d i e s e Zahlen? m = 60 h + em ; s = 60 m + e s ; t c = 60 b + l c ; So i s t s b e s s e r. s t a t i c f i n a l s h o r t MINUTES PER HOUR = 6 0 ; s t a t i c f i n a l s h o r t SECONDS PER MINUTE = 6 0 ; s t a t i c f i n a l s h o r t CLIPS PER BOX = 6 0 ;... minutes = MINUTES PER HOUR h o u r s + e x t r a M i n u t e s ; s e c o n d s = SECONDS PER MINUTE minutes + e x t r a S e c o n d s ; t o t a l C l i p s = CLIPS PER BOX boxes + l o o s e C l i p s ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 15 / 33 Hartcodiert: String-Literale im Code t r y s t o r e. o p e n S t o r e (. / c o n f i g. xml, PSA ) ; manager. r e a d C o n f i g u r a t i o n ( s t o r e ) ; c a t c h ( T r e e S t o r e E x c e p t i o n e ) System. e r r. p r i n t l n ( Konnte K o n f i g u r a t i o n s d a t e i n i c h t l e s e n. ) ; c a t c h ( C o n f i g E x c e p t i o n x ) System. e r r. p r i n t l n ( F e h l e r beim A u s l e s e n d e r K o n f i g u r a t i o n s d a t e i. ) ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 16 / 33
Character sind zwar Zahlen, aber Wie b i t t e? i f ( ( c >= 65) && ( c <= 90) )... i f ( ( c >= A ) && ( c <= Z ) )... Ach so! i f ( C h a r a c t e r. i s U p p e r C a s e ( c ) ) Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 17 / 33 Sprachkonstrukte zur Berechnung von Größen Doppelte Z a h l e n r e f e r e n z c h a r buf [ ] = new c h a r [ 1 0 2 4 ] ; f o r ( i n t i = 0 ; i < 1024; i ++) Sprachmechanismus nutzen! c h a r buf [ ] = new c h a r [ 1 0 2 4 ] ; f o r ( i n t i = 0 ; i < buf. l e n g t h ; i ++) Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 18 / 33
Überflüssige Kommentare / d e f a u l t / d e f a u l t : break ; / r e t u r n SUCCESS / r e t u r n SUCCESS ; zerocount++: / I n c r e m e n t z e r o e n t r y c o u n t e r / / I n i t i a l i z e t o t a l to numberreceived. / Node. t o t a l = Node. numberreceived ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 19 / 33 Überflüssige Kommentare w h i l e ( ( ( c = getchar ( ) )!= EOF) && ( i s S p a c e ( c ) ) ) ; / s k i p w h i t e s p a c e / i f ( c == EOF) / end o f f i l e / t y p e = END OF FILE ; e l s e i f ( c == ( ) / l e f t paren / t y p e = LEFT PAREN ; e l s e i f ( c == ) ) / r i g h t paren / t y p e = RIGHT PAREN ; e l s e i f ( c == ; ) / s e m i c o l o n / t y p e = SEMICOLON ; e l s e i f ( isop ( c ) ) / o p e r a t o r / t y p e = OPERATOR; e l s e i f ( i s D i g i t ( c ) ) / number / t y p e = NUMBER;... Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 20 / 33
Verschluckte (hicks) Exceptions t r y F i l e O u t p u t S t r e a m out = new F i l e O u t p u t S t r e a m ( strname ) ;... out. f l u s h ( ) ; out. c l o s e ( ) ; c a t c h ( I O E x c e p t i o n e ) ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 21 / 33 idkldw i n t f ( i n t f [ ], i n t l, Item k ) i n t i ; f o r ( i =0; i < l ; i ++) i f ( f [ i ] == k ) r e t u r n i ; In der Kürze liegt die Würze (idkldw)? i n t I n d e x ( i n t f i e l d, i n t l e n g t h, Item key ) i n t i ; f o r ( i =0; i < l e n g t h ; i ++) i f ( f i e l d [ i ] == key ) r e t u r n i ; Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 22 / 33
Software-Redundanz for (i = 1; i < MAX; i++) x = func() * y + x; for (i = 1; i < MAX; i++) x = func() * y + x; for (j = 1; j < MAX; j++) x = func() * y + x; foo.c bar.c fred.c for (i = 1; i < MAX; i++) x1 = func() * y1 + x1; for (i = 1; i < MAX; i++) x2 = func() * y2 + x2; Typisch: 5 30 % des Codes sind redundant... Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 23 / 33 Software-Redundanz foo.c bar.c fred.c set_coordinate (&x, y); set_coordinate (&x, y); set_coordinate (&x, y); void set_coordinate ( float *x, float y) int i; for (i = 1; i < MAX; i++) *x = func() * y + *x; set_coordinate (&x1, y1); set_coordinate (&x2, y2);... und können abstrahiert werden Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 24 / 33
Mai 31, 05 7:18 Seite 1/12 5 negation (we eliminate it) 10 branch emitted. AstStatement* over) 40 AstConditionalExpression* conditional = p > ConditionalExpressionCast(); 55 65 EmitBranch(OP_GOTO, Dienstag Mai 31, 2005 1/12 Mai 31, 05 7:18 Seite 3/12 EmitBranchIfExpression(conditional > test_expression, false, 150 155 170 180 lab2: EmitBranchIfExpression(conditional > test_expression, false, EmitBranchIfExpression(conditional > test_expression, false, lab1, 190 EmitBranchIfExpression(conditional > false_expression, cond, lab, over); 200 205 semantic.reportsemerror(semanticerror::array_overflow, instanceof > type); 210 Dienstag Mai 31, 2005 3/12 Mai 31, 05 7:18 Seite 5/12 EmitBranch(OP_GOTO, 305 branch_if(a&&b, true, lab) => case AstBinaryExpression::OR_OR: 330 branch_if(true b, cond, lab) => branch_if(true, cond, lab); Dienstag Mai 31, 2005 5/12 Mai 31, 05 7:18 Seite 2/12 80 EmitBranchIfExpression(conditional > false_expression, true, 85 EmitBranch(OP_GOTO, EmitBranchIfExpression(conditional > test_expression, false, 2/12 Dienstag Mai 31, 2005 Mai 31, 05 7:18 Seite 4/12 215 EmitExpression(expr, false); 220 expr > BinaryExpressionCast()) a String concat 265 left_type > IsSubtype(right_type)) AstExpression* right = StripNops(bp > right_expression); 275 switch (bp > Tag()) 280 branch_if(false&&b, cond, lab) => branch_if(false, cond, lab); 4/12 Dienstag Mai 31, 2005 Mai 31, 05 7:18 Seite 6/12 EmitBranch(OP_GOTO, 355 branch_if(a b,true,lab) => 360 branch_if(b,false,lab); case AstBinaryExpression::XOR: ^ on booleans is equavalent to!= 380 case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: 390 if (left_type == right_type) 395 405 EmitBranch(OP_GOTO, EmitBranch(cond? OP_IFNONNULL : OP_IFNULL, 410 (IsOne(left) IsOne(right))) EQUAL_EQUAL), 415 6/12 Dienstag Mai 31, 2005 Mai 31, 05 7:18 Seite 7/12 left_type == control.boolean_type) 435 cond == (bp > Tag()!= AstBinaryExpr ession::equal_equal), 460 EmitExpression(IsZero(left)? right : left); EmitBranch((cond? OP_IFNE : OP_IFEQ), EmitExpression(right); 475 EmitBranch((cond? OP_IF_ACMPNE : OP_IF_ACMPEQ), EmitBranchIfExpression(IsZero(left)? right : left, cond, Dienstag Mai 31, 2005 7/12 580 op_false = OP_IFLT; 585 op_false = OP_IFGE; 590 op_false = OP_IFGT; 595 600 EmitExpression(left); case AstBinaryExpression::LESS: 620 assert(false); 625 Mai 31, 05 7:18 Seite 9/12 Dienstag Mai 31, 2005 9/12 case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: case AstBinaryExpression::LESS: case AstBinaryExpression::LESS_EQUAL: case AstBinaryExpression::GREATER: case AstBinaryExpression::GREATER_EQUAL: 740 switch (bp > Tag()) 745 op_false = OP_IFNE; 750 op_false = OP_IFEQ; 755 op_false = OP_IFGE; 760 op_false = OP_IFGT; 765 op_false = OP_IFLE; Mai 31, 05 7:18 Seite 11/12 opcode = OP_DCMPL; Dienstag Mai 31, 2005 11/12 Mai 31, 05 7:18 Seite 8/12 490 case AstBinaryExpression::AND: default: 550 8/12 Dienstag Mai 31, 2005 650 case AstBinaryExpression::LESS: EmitExpression(right); opcode = OP_LCMP; 690 assert(false); 695 Mai 31, 05 7:18 Seite 10/12 10/12 Dienstag Mai 31, 2005 775 EmitBranch (cond? op_true : op_false, Mai 31, 05 7:18 Seite 12/12 12/12 Dienstag Mai 31, 2005 Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 25 / 33 Überlange Methoden java provides a variety of conditional branch instructions, so that a number of operators merit special handling: constant operand equality?: && and (partial evaluation) comparisons Other expressions are just evaluated and the appropriate TODO: return a bool that is true if the statement being branched over is even needed (if statements and other places might have a constant false expression, allowing the next block of code to be skipped entirely). 15 void ByteCode::EmitBranchIfExpression(AstExpression* p, bool cond, Label& lab, p = StripNops(p); 20 assert(p > Type() == control.boolean_type); if (p > IsConstant()) if (IsZero(p)!= cond) 25 EmitBranch(OP_GOTO, AstPreUnaryExpression* pre = p > PreUnaryExpressionCast(); 30 if (pre) must be! branch_if(!e,c,l) => branch_if(e,!c,l) 35 assert(pre > Tag() == AstPreUnaryExpression::NOT); if (cond) EmitBranchIfExpression(conditional > test_expression, true, 75 Label skip; EmitBranchIfExpression(conditional > test_expression, true, skip, over); EmitBranchIfExpression(conditional > false_expression, false, DefineLabel(skip); CompleteLabel(skip); 90 if (IsZero(conditional > true_expression)) branch_if(expr?false:true, c, l) => branch_if(expr,! c, l); branch_if(expr?false:false, c, l) => expr, branch if! c 95 branch_if(expr?false:b, c, l) => branch_if(!expr && b, c, l); if (IsOne(conditional > false_expression)) EmitBranchIfExpression(conditional > test_expression, 100! cond, if (IsZero(conditional > false_expression)) EmitExpression(conditional > test_expression, false); 105 if (! cond) 420 if (control.issimpleintegervaluetype(left_type) assert(control.issimpleintegervaluetype(right_type) 425 right_type == control.boolean_type); if (IsZero(left) IsZero(right)) if (left_type == control.boolean_type) 430 One of the operands is false. Branch on the other. EmitBranchIfExpression(IsZero(left)? right : left, 440 One of the operands is zero. Only emit the other. 445 if (bp > Tag() == AstBinaryExpression::EQUAL_EQUAL) EmitBranch((cond? OP_IFEQ : OP_IFNE), 450 EmitExpression(left); EmitExpression(right); One argument is true. Emit the other, and result is true. 495 if (IsOne(left) IsOne(right)) EmitExpression(IsOne(left)? right : left, false); if (cond) EmitBranch(OP_GOTO, 500 505 One argument is true. Branch on other. if (IsOne(left) IsOne(right)) EmitBranchIfExpression(IsOne(left)? right : left, 510 cond, 515 One argument is false. Emit the other, and result is false. if (IsZero(left) IsZero(right)) EmitExpression(IsZero(left)? right : left, false); 520 if (! cond) EmitBranch(OP_GOTO, EmitBranchIfExpression(pre > expression,! cond, if (conditional) if (conditional > test_expression > IsConstant()) 45 branch_if(true?a:b, cond, lab) => branch_if(a, cond, lab); branch_if(false?a:b, cond, lab) => branch_if(b, cond, lab); EmitBranchIfExpression((IsZero(conditional > test_expression) 50? conditional > false_expression : conditional > true_expression), cond, if (IsOne(conditional > true_expression)) branch_if(expr?true:true, c, l) => expr, branch if c branch_if(expr?true:false, c, l) => branch_if(expr, c, l); branch_if(expr?true:b, c, l) => branch_if(expr b, c, l); 60 if (IsOne(conditional > false_expression)) if (! cond) 110 EmitBranchIfExpression(conditional > test_expression, true, EmitBranchIfExpression(conditional > false_expression, false, 115 Label skip; EmitBranchIfExpression(conditional > test_expression, true, skip, over); 120 EmitBranchIfExpression(conditional > false_expression, true, DefineLabel(skip); CompleteLabel(skip); 125 if (IsOne(conditional > false_expression)) branch_if(expr?a:true, c, l) => branch_if(!expr a, c, l); 130 if (cond) 455 if (bp > Tag() == AstBinaryExpression::EQUAL_EQUAL) EmitBranch((cond? OP_IF_ICMPEQ : OP_IF_ICMPNE), EmitBranch((cond? OP_IF_ICMPNE : OP_IF_ICMPEQ), 465 Both operands are reference types: just do the comparison. if (IsReferenceType(left_type)) assert(isreferencetype(right_type)); 470 EmitExpression(left); if (bp > Tag() == AstBinaryExpression::EQUAL_EQUAL) EmitBranch((cond? OP_IF_ACMPEQ : OP_IF_ACMPNE), EmitExpression(conditional > test_expression, false); if (cond) if (IsZero(conditional > false_expression)) EmitBranchIfExpression(conditional > test_expression, 70 cond, 135 EmitBranchIfExpression(conditional > true_expression, true, 140 Label skip; 480 case AstBinaryExpression::IOR: One argument is false. Branch on other. 485 if (IsZero(left) IsZero(right)) 525 default: 530 here if not comparison, comparison for non integral numeric types, or integral comparison for which no special casing needed. Begin by dealing with non comparisons switch (bp > Tag()) 535 case AstBinaryExpression::LESS: case AstBinaryExpression::LESS_EQUAL: case AstBinaryExpression::GREATER: case AstBinaryExpression::GREATER_EQUAL: 540 case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: break to continue comparison processing 545 not a comparison, get the (necessarily boolean) value of the expression and branch on the result EmitExpression(p); EmitBranch(cond? OP_IFNE : OP_IFEQ, 555 Opcode opcode = OP_NOP, op_true, op_false; skip, over); EmitBranchIfExpression(conditional > true_expression, false, 145 DefineLabel(skip); CompleteLabel(skip); if (IsZero(conditional > false_expression)) We know the result: false. But emit the left expression, in case of side effects in (expr? null : null). if (! cond) EmitBranch(OP_GOTO, if (expr > IsConstant() a String constant assert(left_type!= control.boolean_type); 560 if (control.issimpleintegervaluetype(left_type)) we have already dealt with EQUAL_EQUAL and NOT_EQUAL for the case of two integers, but still need to look for comparisons for which 565 one operand may be zero. if (IsZero(left)) switch (bp > Tag()) 630 op_true = OP_IF_ICMPLT; op_false = OP_IF_ICMPGE; 635 case AstBinaryExpression::LESS_EQUAL: op_true = OP_IF_ICMPLE; op_false = OP_IF_ICMPGT; branch_if(expr?a:false, c, l) => branch_if(expr && a, c, l); if (! cond) EmitBranchIfExpression(conditional > true_expression, false, 160 We know the result: true, since the expression is non null and String is a final class. 225 assert(left_type == control.string()); EmitExpression(expr, false); if (cond) EmitBranch(OP_GOTO, 230 if ((expr > ThisExpressionCast() EmitExpression(right); 570 switch (bp > Tag()) case AstBinaryExpression::LESS: if (0 < x) same as if (x > 0) op_true = OP_IFGT; 575 op_false = OP_IFLE; case AstBinaryExpression::LESS_EQUAL: if (0 <= x) same as if (x >= 0) op_true = OP_IFGE; case AstBinaryExpression::GREATER: 640 op_true = OP_IF_ICMPGT; op_false = OP_IF_ICMPLE; case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IF_ICMPGE; 645 op_false = OP_IF_ICMPLT; default: assert(false); Label skip; EmitBranchIfExpression(conditional > test_expression, false, 165 skip, over); EmitBranchIfExpression(conditional > true_expression, true, DefineLabel(skip); CompleteLabel(skip); expr > SuperExpressionCast() expr > ClassLiteralCast() expr > ClassCreationExpressionCast() 235 expr > ArrayCreationExpressionCast()) && We know the result: true, since the expression is non null. case AstBinaryExpression::GREATER: if (0 > x) same as if (x < 0) op_true = OP_IFLT; case AstBinaryExpression::GREATER_EQUAL: if (left_type == control.long_type) 655 EmitExpression(left); 175 branch_if(expr?a:b, c, l) => branch_if(expr, false, lab1) branch_if(a, c, l) goto lab2 lab1: branch_if(b, c, l) Label lab1, lab2; over); 185 EmitBranchIfExpression(conditional > true_expression, cond, lab, over); EmitBranch(OP_GOTO, lab2, over); DefineLabel(lab1); CompleteLabel(lab1); DefineLabel(lab2); CompleteLabel(lab2); 240 EmitExpression(expr, false); if (cond) EmitBranch(OP_GOTO, 245 EmitExpression(expr); PutOp(OP_INSTANCEOF); PutU2(RegisterClass(right_type)); 250 EmitBranch((cond? OP_IFNE : OP_IFEQ), 255 dispose of non binary expression case by just evaluating operand and emitting appropiate test. AstBinaryExpression* bp = p > BinaryExpressionCast(); 260 if (! bp) EmitExpression(p); EmitBranch((cond? OP_IFNE : OP_IFEQ), if (0 >= x) same as if (x <= 0) op_true = OP_IFLE; default: assert(false); if (IsZero(right)) switch (bp > Tag()) op_true = OP_IFLT; 605 op_false = OP_IFGE; case AstBinaryExpression::LESS_EQUAL: op_true = OP_IFLE; op_false = OP_IFGT; 610 case AstBinaryExpression::GREATER: 660 branch according to result value on stack switch (bp > Tag()) 665 case AstBinaryExpression::EQUAL_EQUAL: op_true = OP_IFEQ; op_false = OP_IFNE; case AstBinaryExpression::NOT_EQUAL: 670 op_true = OP_IFNE; op_false = OP_IFEQ; case AstBinaryExpression::LESS: op_true = OP_IFLT; 675 op_false = OP_IFGE; case AstBinaryExpression::LESS_EQUAL: op_true = OP_IFLE; op_false = OP_IFGT; 680 case AstBinaryExpression::GREATER: 195 AstInstanceofExpression* instanceof = p > InstanceofExpressionCast(); if (instanceof) AstExpression* expr = StripNops(instanceof > expression); TypeSymbol* left_type = expr > Type(); TypeSymbol* right_type = instanceof > type > symbol; if (right_type > num_dimensions > 255) if (left_type == control.null_type) Here if binary expression, so extract operands 270 AstExpression* left = StripNops(bp > left_expression); TypeSymbol* left_type = left > Type(); TypeSymbol* right_type = right > Type(); case AstBinaryExpression::AND_AND: branch_if(true&&b, cond, lab) => branch_if(b, cond, lab); op_true = OP_IFGT; op_false = OP_IFLE; 615 case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IFGE; op_false = OP_IFLT; default: EmitExpression(left); EmitExpression(right); op_true = OP_IFGT; op_false = OP_IFLE; 685 case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IFGE; op_false = OP_IFLT; default: if (left_type == control.float_type) EmitExpression(left); EmitExpression(right); if (left > IsConstant()) if (IsOne(left)) 285 EmitBranchIfExpression(right, cond, if (! cond) EmitBranch(OP_GOTO, 290 branch_if(a&&true, cond, lab) => branch_if(a, cond, lab); branch_if(a&&false, cond, lab) => emit(a), pop; for side effects if (right > IsConstant()) 295 if (IsOne(right)) EmitBranchIfExpression(left, cond, EmitExpression(left, false); 300 if (! cond) branch_if(a,false,skip); branch_if(b,true,lab); skip: branch_if(a&&b, false, lab) => 310 branch_if(a,false,lab); branch_if(b,false,lab); if (cond) 315 Label skip; EmitBranchIfExpression(left, false, skip, over); EmitBranchIfExpression(right, true, DefineLabel(skip); CompleteLabel(skip); 320 EmitBranchIfExpression(left, false, EmitBranchIfExpression(right, false, 325 branch_if(false b, cond, lab) => branch_if(b, cond, lab); if (left > IsConstant()) if (IsZero(left)) 335 EmitBranchIfExpression(right, cond, if (cond) EmitBranch(OP_GOTO, 340 branch_if(a false, cond, lab) => branch_if(a, cond, lab); branch_if(a true, cond, lab) => emit(a), pop; for side effects if (right > IsConstant()) 345 if (IsZero(right)) EmitBranchIfExpression(left, cond, EmitExpression(left, false); 350 if (cond) branch_if(a,true,lab); branch_if(b,true,lab); branch_if(a b,false,lab) => branch_if(a,true,skip); skip: if (cond) 365 EmitBranchIfExpression(left, true, EmitBranchIfExpression(right, true, 370 Label skip; EmitBranchIfExpression(left, true, skip, over); EmitBranchIfExpression(right, false, DefineLabel(skip); CompleteLabel(skip); 375 assert(left_type == control.boolean_type); Fallthrough! One of the operands is null. We must evaluate both operands, to get any side effects in (expr? null : null). 385 if (left_type == control.null_type right_type == control.null_type) EmitExpression(left, left_type!= control.null_type); EmitExpression(right, right_type!= control.null_type); if (cond == (bp > Tag() == AstBinaryExpression::EQUAL_EQUAL)) if (bp > Tag() == AstBinaryExpression::EQUAL_EQUAL) 400 EmitBranch(cond? OP_IFNULL : OP_IFNONNULL, One of the operands is true. Branch on the other. if (left_type == control.boolean_type && EmitBranchIfExpression(IsOne(left)? right : left, cond == (bp > Tag() == AstBinaryExpression:: Both operands are integer. switch (bp > Tag()) 700 opcode = OP_FCMPL; op_true = OP_IFEQ; op_false = OP_IFNE; 705 opcode = OP_FCMPL; op_true = OP_IFNE; op_false = OP_IFEQ; 710 opcode = OP_FCMPG; op_true = OP_IFLT; op_false = OP_IFGE; 715 opcode = OP_FCMPG; op_true = OP_IFLE; op_false = OP_IFGT; 720 opcode = OP_FCMPL; op_true = OP_IFGT; op_false = OP_IFLE; 725 opcode = OP_FCMPL; op_true = OP_IFGE; op_false = OP_IFLT; 730 default: assert(false); 735 if (left_type == control.double_type) EmitExpression(left); EmitExpression(right); case AstBinaryExpression::EQUAL_EQUAL: opcode = OP_DCMPL; op_true = OP_IFEQ; case AstBinaryExpression::NOT_EQUAL: opcode = OP_DCMPL; op_true = OP_IFNE; case AstBinaryExpression::LESS: opcode = OP_DCMPG; op_true = OP_IFLT; case AstBinaryExpression::LESS_EQUAL: opcode = OP_DCMPG; op_true = OP_IFLE; case AstBinaryExpression::GREATER: opcode = OP_DCMPL; op_true = OP_IFGT; case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IFGE; 770 op_false = OP_IFLT; default: assert(false); assert(false && "comparison of unsupported type"); if (opcode!= OP_NOP) 780 PutOp(opcode); if need to emit comparison before branch Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 26 / 33
Ignoranz, Not-Invented-Here-Syndrom oder die neuerfundenen Räder p u b l i c c l a s s A r t i c l e s p r i v a t e A r t i c l e item ; p r i v a t e A r t i c l e s n e x t ; p u b l i c A r t i c l e s ( )... p u b l i c v o i d Add ( A r t i c l e a r t )... p u b l i c v o i d Show ( )... p u b l i c c l a s s A r t i c l e s p r i v a t e j a v a. u t i l. L i n k e d L i s t a r t i c l e s ; p u b l i c A r t i c l e s ( )... p u b l i c v o i d Add ( A r t i c l e a r t )... p u b l i c v o i d Show ( )... Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 27 / 33 Die Oglala des 21. Jahrhunderts p u b l i c c l a s s A r t i c l e s p r i v a t e j a v a. u t i l. L i n k e d L i s t a r t i c l e s ; p u b l i c A r t i c l e s ( )... p u b l i c v o i d Add ( A r t i c l e a r t ) a r t i c l e s. addlast ( a r t ) ; p u b l i c v o i d Show ( ) L i s t I t e r a t o r l i s t I t r = a r t i c l e s. l i s t I t e r a t o r ( ) ; w h i l e ( l i s t I t r. hasnext ( ) ) A r t i c l e a r t = ( A r t i c l e ) l i s t I t r. n e x t ( ) ; a r t. show ( ) ; Oglala (bedeutet: Die ihre Habe verschleudern im Sinne von Großzügigkeit) sind ein Stamm der Lakota-Sioux-Indianer. Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 28 / 33
Prinzipien einheitlich so einfach wie möglich sprechend, direkt verständlich prägnant frei von Redundanz übersichtlich strukturiert abgeschlossen abstrakt Separation of Concerns Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 29 / 33 Was alles in den Code-Inspektionen 2004/05 auffiel Verwendung von verketteten Listen, wo Maps angebracht wären; manuelle der entsprechenden Map-Zugriffe Verwendung von verketteten Listen, wo ArrayList angebrachter wäre; z.b. Iterieren durch die LinkedList über Indexzugriffe alle Methoden einer Klasse static; die statischen Variablen werden über den Konstruktor initialisiert alle Methoden einer Klasse static, die Instanz, auf der die Methoden arbeiten, werden z.b. als LinkedList jeweils übergeben Neuimplementierung von Sortieralgorithmen die gesamte GUI wird in einer einzigen Klasse implementiert Datenbankzugriffe werden über alle Klassen verteilt, statt gekapselt Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 30 / 33
Was alles in den Code-Inspektionen 2004/05 auffiel Query wird mit select * gemacht, danach werden manuell die benötigten Spalten rausgefiltert Datenbanknamen usw. werden hartcodiert manuelle von Parsern für verschiedene Zwecke (wo z.b. XML oder Properties-Datei angebracht wäre) mehrfache der gleichen Hilfsklassen von verschiedenen Leuten, z.b. Übersetzungen (dementsprechend auch mit verschiedenen Dateiformaten) keine Berücksichtigung von Performance (z.b. bei Operationen auf verketteter Liste, Dateioperationen; Konfigurationsdatei wird bei jedem Methodenaufruf neu eingelesen) Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 31 / 33 Wiederholungsfragen Was sind Refactorings und Bad Smells? Wie wird Refactoring durchgeführt? Nennen Sie Beispiele für Bad Smells. Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 32 / 33
1 Murphy u. a. 1995 Murphy, Gail C. ; Notkin, David ; Sullivan, Kevin: Software Reflexion Models: Bridging the Gap Between Source and High-Level Models. In: Proc. of the Third ACM SIGSOFT Symposium on the Foundations of Software Engineering, 1995, S. 18 28 2 Murphy u. a. 2001 Murphy, Gail C. ; Notkin, David ; Sullivan, Kevin J.: Software Reflexion Models: Bridging the Gap between Design and Implementation. In: IEEE Transactions on Software Engineering 27 (2001), April, Nr. 4, S. 364 380 3 Object Management Group 2003 Object Management Group: OMG Unified Modeling Language Specification. March 2003. Version 1.5 4 Sun microsystems 1999 Sun microsystems: Code Conventions for the Java TM Programming Language. April 1999. URL http: java.sun.com/docs/codeconv/html/codeconvtoc.doc.html Rainer Koschke (Uni Bremen) Software-Projekt Wintersemester 2006/07 33 / 33