Vous êtes sur la page 1sur 5

ES – TESTE 2

Aula 11
 Design as Structure

Qualities of a good design:


- High Cohesion (single responsibility within a module) – increases locality of change; Person contains
both domain logic and database access;
- Low Coupling (reduces dependencies between modules) – reduces change propagation; Interface does
not completely hide the database structure (insert, update)

Design Principles:
- Open Close P: Modules should be open for extension but closed for modifications;
- Dependency Inversion P: High-level modules should not depend on low-level modules; Both should
depend on abstractions; Abstractions should not depend on details; Details should depend on abstractions.
- Interface Segregation P: Clients should not be forced to depend upon interfaces that they don’t use;
- Single Responsibility P: A module should have only one reason to change;
- Liskov’s Substitution P: Derived types must be completely substitutable for their base types;

Interfaces and Abstractions


Interfaces hide an implementation – low coupling, encapsulation
Types of Interfaces:
- Exposes attributes: no encapsulation;
- Contains complex entities as parameters: shared data model; the caller depends on the structure of the
parameter and needs to change whenever it changes;
- Only contains simple data types: no shared data model; the caller only depends on the programming
language of the interface.
- Is programming language independent: WSDL; it further reduces coupling because the caller does not
depend on the programming language that implements the interface.
- Contains meta-model: XML Schema; The interface is self-contained because it describes itself. It
reduces coupling because the caller knows at runtime what is the structure of the data being passed. Note,
that complex entities can be passed but the interface contains the schema that defines the complex entities
and expects the caller to interpret them and adapt its behavior accordingly
- Easy to define: provides low coupling;

A good interface depends on a good abstraction. Abstractions depend on the context.


Analysis Paralysis: dev try to find the right abstractions before starting implementing the functionality;
The interface hides the implementations but exposes the abstraction;

How to define the right abstractions?

 Design as a Process: the design is also a process, the set of activities that produce the structure called
design. This process is responsible to create the structure that is a solution to the set of requirements.
defines the bridge between the problem space, the requirements, and the solution space, the structure
of the code, such that the latter satisfies the former.

Top Down: from requirements to design structure; from the problem space to the solution space; departs
from the requirements and identifies the structure that should fulfil them. Occurs before the implementation
starts; Design the system by successive decompositions where modules are decomposed into more
detailed modules.
Bottom Up: refactoring of implemented functionality; intertwines designing and coding, usually defined as
refactoring; Dev are wither incrementing the system functionality or refactoring its structure. Therefore, the
abstractions are made to measure the set of functionalities the system is currently implementing. There is
no extra complexity in the code. Refactoring requires a test-driven approach because the changes to the
structure should not break any of the existing functionality.
Aula 12
- Software Design:
 Bottom-Up Design Process
How do statically type OO languages expect programs to evolve? First abstract classes, then
concrete classes, then objects. But abstractions depend on the context… concrete cases first,
abstractions after.
How top-down approaches define abstractions? Analyze several cases, use cases…
Can we build abstractions from code cases? Refactoring. We move from a small set of code cases to
abstractions. Which one? The abstraction that fits the already implemented cases (consider the
known cases). Evolve the abstraction as more cases need to be considered (evolution of
abstractions). It is necessary to keep the code running (regressive testing).

 Refactoring: add functionality, test, change structure, test, repeat.

 The code that is going to change is only removed at the end. If the code was removed
at the begin the functionality would break.
 Introduce code if smaller refactoring steps are required. This auxiliary code is only there
to avoid big gaps during the change, which may break the code, and it is removed at
the end, when the refactoring is complete.
 When a bug is found for which there isn’t a test that fails, write the test before starting
the debug. This increases the coverage of tests and reduce the cost of change in the
future.
 Either introduce new functionality or refactor code, do not do both at the same time.
Refactoring is finding the structure that best fits a set of working functionalities.

*ver exemplo*
The integration of test-first programming and refactoring results on test-driven development. A method
which has three steps: (1) write a test that fails but specifies a required functionality; (2) Implement the
functionality such that the test passes; (3) refactor the code such that the structure has the abstractions
that fit the implemented functionality.

Aula 13
Workflows of Refactoring

Why 2 phases? Green: While making the test work, we can focus just on the problem of adding the new
functionality, without thinking about how this functionality should be best structured. Refactor: Once things
are working, we can now concentrate on good design, while working in the safer refactoring mode of small
steps on a green test base.
Litter-Pickup Refactoring: always leave the code better than when you found it.
Comprehension Refactoring: whenever you have to figure out what code id doing, you are building some
understanding in your head. Once you’ve build it, you should move that understanding into the code so
nobody has to build it from scratch in their head again.

Preparatory Refactoring: often you start working on adding new functionality


and you realize the existing structures don’t play well with what you’re about to
do. So, it usually pays to begin by refactoring the existing code into the shape
you now know is the right shape for what you’re about to do.

Planned Refactoring: failed to do refactoring while working. Many teams schedule refactoring as part pf
their planned work, using “refactoring stories”, to fix larger areas on problematic code that needs dedicated
attention. It’s a necessary element but also a sign that the team hasn’t done enough refactoring using other
workflows.

Long-term Refactoring: branch by abstraction. Some restructuring requires bigger changes that can be
done in a single dev episode. This can still be done using refactoring. The team needs to agree on a rough
end-state as well as a rough plan to get there, then during their regular work they can take the opportunity
to carry out refactorings that move the architecture towards the desired direction. The code base can
remain in a working state even as features are added.

- Refactoring makes it easier to understand the code – which makes subsequent changes quicker and
cheaper.
- Preparatory refactoring can pay for itself when adding the feature you’re preparing for.
- Don’t refactor unless you think you will recoup your investment later by quicker work.
- Refactoring should be done in conjunction with adding new features.
- Use refactoring to make things cleaner, but don’t try to completely fix things. The key is gradual
improvement through many passes through the codebase.
- Refactoring – Clean Code – Faster Delivery

Introduce Persistence using the FenixFramework

Run tests – make tests transactional – run tests – make class persistent – run tests

Create persistence tests – associate class with other persistent entities – add to persistence test – run tests
– make class attributes persistent – add to persistent test – run tests.

Aula 14
-- Software Reuse
Due to increasing need of software it is essential to leverage on existing software. There are several
approaches: libraries, frameworks, code generators, product-lines, services and patterns.
- Libraries: the software uses the software developed by another team through the invocation of an
interface. The code being reused is bounded together with the code being developed in the final executable
package (collections). Libraries base their adaptation on the parameterization of the interface, the
abstraction is customized by giving different values to the interface parameters.
- App Frameworks: define a generic structure that is extended by the application being developed.
Frameworks follow the inversion of control principle, it is the framework code that calls the application-
specific code. The execution starts in the framework code and executes the application specific-code
according to the structure superimposed by the framework (Django for Python). Application frameworks
explore the use of inheritance by defining hook methods where the application-specific code is invoked from
framework code. These hook methods are part of abstract classes which can be extended, adapted, to the
application-specific needs.
- Code generators: generate code given a description. The generated code is reused and adapted
(consider the specification of a web-service using WSDL. The generator is able to produce the code that
enables the web-service to be invoked using the SOAP protocol). each web-service differs in terms of its
name, and the type and number of parameters, which requires the generator to adapt the generation for
each concrete specification. (used in domain-specific languages and model-driven eng, which intended to
reduce the nr of transformations associated with the software dev process by providing higher languages
that are closer to the problem domain and that are executable. Code generator transforms there HL
languages and models into executable code). Code generators have more powerful mechanisms of
adaptation because they can be defined at an higher level. Adaptation is achieved by writing sentences
using the domain specific-language or designing models, which has a certain level of independence of the
reused code and has the advantage that the generated code does not need to be human readable.
- Product-Lines: split the software artefact into a set of modules that can be assembled to produce slightly
different products. This is also called a family of products, where several variations of the product are
supported. Any product of a product family (ex: OS) reuses some common modules and assembles them
with the modules that provide the specific variations. Product-lines require complex software configuration
and software build strategies to manage the different versions of each module and all their consistent
combinations. Product-lines have different implementations for some of the modules and define different
builds for each product instance of the product family. However, it is also possible to assemble the modules
during runtime but is it not a frequent requirement.
- Services: are “executable and independently deployed libraries”. A software system can use, during its
execution, the services provided by another executing system. Reuse occurs because the service can be
shared. The integration of “use of the code” with “use of the process that executes the code” is one of the
driving forces of the cloud and it is responsible for new business models for software like pay-per-use
(Paypal, authentication). Services implement interfaces that are published in registries where clients can
search them. Since clients are not dependent on a specific service interface they can adapt to the provided
interface. Clients adaptation can take advantage of the published interface if it includes, besides the
signature, meta-information about the quality of the provided service.
- Patterns: are descriptions of solutions for recurring problems. Patterns describe knowledge that can be
reused by developers and which is twofold, knowledge of the problem and knowledge of the solution.
Although not used as an execution artefact, this kind of reuse establishes a common language of best
practices that is shared among the members of a community.

* Junit
* Spring Boot

Aula 15
Software Architecture: is the system high design; should satisfy stakeholders needs and demonstrates
system qualities.
Architecture’s goal: it establishes the systemic qualities of a software system and these qualities have to
support the system stakeholders’ needs (these needs are associated to how the stakeholders perceive the
system and correspond to non-functional requirements).
So, the software architecture is a bridge between the problem space and the solution space and intends to
guarantee that the proposed solution, the architecture, will be able to fulfil the stakeholders’ needs. (needs
– security, time to market, performance, maintainability, availability), (architectural stakeholders – client,
end user, dev team, business team). The architectural design is the design from the perspective of
stakeholders, the parts of the system that stakeholders want to know about in order to be sure that the
system will fulfil their needs (stakeholders needs = system qualities), requires tradeoffs sometimes.
Therefore, the work of a software architect consists on a clear definition of the system qualities, its non-
functional requirements, such that all the stakeholders agree on the compromises taken to define them, and
on the definition of a design of the system that shows that the system will consider the identified qualities.
The software architect mixes the roles of requirements engineer and software designer.
- Architectural Views: logical view, physical view, process view, dev view, module/code view,
component/runtime view (Diff perspectives on the system architecture).
- Architectural Patterns: we need them bc they restrict nr of possible forms, vocabulary, each pattern
provides different qualities.

- Application Architectures:

Architectural patterns define application independent solutions.


An application architecture is an architecture for a type of system.
Transaction Processing Systems, Information Systems, Language Processing Systems
The project software architecture combines architectural patterns and app architectures:
* Information system • Transaction processing system • Model-view-controller • Repository • Client-server •
Layered
Different Views: Component View, Module View

Aula 16

Vous aimerez peut-être aussi