= SoftwareArchitecture =
Extracted and adapted from http://www.bredemeyer.com/pdf_files/ArchitectureDefinition.PDF

 * http://www.jiludwig.com/reiber/requirements_trace.html 

== Architecture Views ==

=== Conceptual Architecture ===
The Conceptual Architecture identifies the high-level components of the system, and the relationships
among them. Its purpose is to direct attention at an appropriate decomposition of the system without delv-
ing into details. 

Goals:
 * identification of components and allocation of responsibilities to components

=== Logical Architecture ===
In Logical Architecture, the externally visible properties of the components are made precise and unambiguous through well-defined interfaces and component specifications, and key architectural mechanisms are detailed. 

Goals:
 * design of component interactions, connection mechanisms and protocols (exchanged messages); 
 * interface design and specification; providing contextual information for component users

=== Execution Architecture ===
An Execution Architecture is created for distributed or concurrent systems. The process view shows the
mapping of components onto the processes of the physical system, with attention being focused on such
concerns as throughput and scalability. 

 * assignment of the runtime component instances to processes,threads and address spaces; 
 * how they communicate and coordinate; 
 * how physical resources are allocated to them

== UML simple steps ==
Reference: http://www.sparxsystems.com/resources/tutorial/uml_tutorial2.html

Steps:
 * Create use cases based on the user goals and how those goals are achieved by interacting with the system
 * Detail each use case with a best case scenario
 * With the details of the use cases, begin to construct a domain model (high level business objects), sequence diagrams, collaboration/communication diagrams and user interface models. These describe the 'things' in the new system, the way those things interact and the interface a user will use to execute use case scenarios.
 * With the domain model start to create a class model.
 * The class model is a precise specification of the objects in the system, their data or attributes and their behaviour or operations. 
 * A component represents a deployable chunk of software that collects the behaviour and data of one or more classes and exposes a strict interface to other consumers of its services. So from the Class Model a Component Model is built to define the logical packaging of classes. 


http://agilemodeling.com/essays/agileArchitecture.htm

http://www.sparxsystems.com.au/resources/uml2_tutorial/

http://agilemodeling.com/artifacts/useCaseDiagram.htm

http://agilemodeling.com/artifacts/crcModel.htm

http://agilemodeling.com/artifacts/robustnessDiagram.htm

== Recipe 1 - Unified Process - UML - Use case driven ==

SSD (System Sequence Diagram)
Use cases - Behavioral Requirements 

 * Identify use cases and create use case diagrams
 * detail textually each use case (create use case detail)
 * Create class diagram for domain model with only class names based on use case detail
 * Create sequence/communication diagrams (SSD - 1st should be the System Sequence Diagram) that realizes/illustrates the use case
 * Refine the classes diagram with the operations and attributes found in the sequence/communication diagram

{{{
Use case:
Actors:
Goals:
Main scenario
1. The system ...
2. The user ...
}}} 


== Use case add numbers ==

{{{
@startuml
actor user
boundary system

system -> user : prompts first number
user -> system : inputs the first number
system -> user : prompts for the second number
user -> system : inputs the second number
system -> user : shows the sum of the two numbers
@enduml
}}}

{{{#!highlight python
'''
Use case: Add numbers
Actors: User
Goals: Add two numbers
Main scenario:
1. The system prompts for the first number
2. The user inputs the first number
3. The system prompts for the second number
4. The user inputs the second number
5. The system shows the sum of the two numbers 

Extensions:
2.a   The first number is invalid
2.a.1 The system shows the message "Please check the inputed value for the first value"
2.a.2 The use case continues at step 1

4.a   The second number is invalid
4.a.1 The system shows the message "Please check the inputed value for the second value"
4.a.2 The use case continues at step 3
 
Postcondition: two numbers are added
'''
# python useCaseAdd.py
def readNumber(prompt,exceptionMessage):
    gotValue=False
    value=0
    while(gotValue==False):
        try:
            value = int( input(prompt) )
            gotValue=True
        except Exception as ex:
            print(exceptionMessage)
    return value
    
first = readNumber('FirstNumber: ','Please check the inputed value for the first value')            
second = readNumber('Second number: ','Please check the inputed value for the second value') 
print('The sum is %d'%(first + second))
}}}


== Add numbers SSD example ==
 * PlantUML online server: http://www.plantuml.com/plantuml/

{{{
@startuml
actor user
boundary system
control business

loop while first number is invalid
  system -> user : prompts first number
  user -> system : inputs the first number

  alt success
    system -> user : First number is valid
  else invalid first number
    system -> user : Please check the inputed value for the first value
  end
end

loop while second number is invalid
  system -> user : prompts second number
  user -> system : inputs the second number

  alt success
    system -> user : second number is valid
  else invalid second number
    system -> user : Please check the inputed value for the second value
  end
end
system -> business : add(first,second)
business --> system : sum
system -> user : shows the sum of the two numbers
@enduml
}}}

{{attachment:addNumbersSSD.png}}

== Functional requirements (High level) ==

Define a high level API, design by contract, interface for the whole system. 
Just one service with a lot of methods that help fullfil the use cases.
Developer point of view. 

=== Functional requirement addNumber ===
In the above diagram the functional requirement FR is the add function that return a sum.
{{{
add(first:int,second:int):int
}}}

The system must be able to add two numbers and return the sum result.

== SSD (System Sequence Diagram) implementation examples ==
ssdBoundary.py
{{{#!highlight python
#!/usr/bin/python3
"""
All logic still in boundary/UI
"""
class Entity:
    """ """
    def __init__(self):
        pass    
    
class Boundary:
    """ """
    def __init__(self):
        pass 
    
class Credencial(Entity):
    """ """
    def __init__(self,utilizador,password):
        """ """
        self.utilizador = utilizador
        self.password = password

class Menu(Entity):
    def __init__(self,nome):
        """ """
        self.nome=nome
        self.opcoes=[]
        
    def adicionarOpcao(self,opcao):
        """ """
        self.opcoes.append(opcao)
        
    def getOpcoes(self):
        """ """
        return self.opcoes
        
class Opcao(Entity):
    def __init__(self,nome,callback):
        """ """
        self.nome=nome
        self.callback = callback

class Cotacao(Entity):
    def __init__(self,nome,valor,data):
        """ """
        self.nome=nome
        self.valor=valor
        self.data=data
    
    def __repr__(self):
        """ """
        return '%s %s %f'%(self.data, self.nome, self.valor)
    
class UI(Boundary):
    def __init__(self):
        """ """
        self.menu=Menu('Menu')
        self.menu.adicionarOpcao(Opcao('Cotações',self.cotacoes))
        self.menu.adicionarOpcao(Opcao('Análises',self.analises))
        self.menu.adicionarOpcao(Opcao('Sair',self.sair))
        
        self.credenciais=[]
        self.credenciais.append( Credencial('vitor','12345678') )
        self.credenciais.append( Credencial('calvin','wally') )
        
        self.cotacoes=[]
        self.cotacoes.append(Cotacao('YHOO',1,'2016-01-02'))
        self.cotacoes.append(Cotacao('CSCO',1,'2016-01-02'))
        self.cotacoes.append(Cotacao('YHOO',2,'2016-01-03'))
        self.cotacoes.append(Cotacao('CSCO',2,'2016-01-03'))

        
    def pedirCredenciais(self):
        """ """
        print('Insira as suas credenciais')
        print('Utilizador:')
        utilizador = input()
        print('Password:')
        password = input()
        return Credencial(utilizador,password)
    
    def validarCredenciais(self,credencial):
        """ """
        found=False
        for c in self.credenciais:
            if(credencial.utilizador==c.utilizador and credencial.password==c.password):
                found=True
                
        if found:
            print('Credenciais válidas')
            return True            
        else:
            print('Credenciais inválidas')
            return False
            
    def mostrarMenu(self):
        for opcao in self.menu.getOpcoes():
            print(' %s'%(opcao.nome))
        opcao=input()
        selOpcao=None
        for o in self.menu.getOpcoes():
            if o.nome==opcao:
                selOpcao=o
        return selOpcao
    
    def cotacoes(self):
        print('Menu Cotações')
        cots=[]
        for c in self.cotacoes:
            if c.nome not in cots:
                cots.append(c.nome)
                print(c.nome)
        print('Escolha a cotação')
        cotacao=input()
        #mostrar cotacões para acção escolhida
        for c in self.cotacoes:
            if c.nome == cotacao:
                print(c)
        
    def analises(self):
        print('Menu Análises')
    
    def sair(self):
        exit(0)
    
if __name__=='__main__':
    ui = UI()
    credencial = ui.pedirCredenciais()
    resultado = ui.validarCredenciais(credencial)
    
    if resultado==True:
        opcao = ui.mostrarMenu()
        opcao.callback()

}}}

ssdControl.py
{{{#!highlight python
#!/usr/bin/python3
"""
All logic in control/service classes 
"""
class Entity:
    """ Model """
    def __init__(self):
        pass    
    
class Boundary:
    """ View """
    def __init__(self):
        pass 

class Control:
    """ Business Logic - Controller """
    def __init__(self):
        pass 
    
class Credencial(Entity):
    """ """
    def __init__(self,utilizador,password):
        """ """
        self.utilizador = utilizador
        self.password = password

class Menu(Entity):
    def __init__(self,nome):
        """ """
        self.nome=nome
        self.opcoes=[]
        
    def adicionarOpcao(self,opcao):
        """ """
        self.opcoes.append(opcao)
        
    def getOpcoes(self):
        """ """
        return self.opcoes
        
class Opcao(Entity):
    def __init__(self,nome,callback):
        """ """
        self.nome=nome
        self.callback = callback

class Cotacao(Entity):
    def __init__(self,nome,valor,data):
        """ """
        self.nome=nome
        self.valor=valor
        self.data=data
    
    def __repr__(self):
        """ """
        return '%s %s %f'%(self.data, self.nome, self.valor)
    
class ControloCredencial(Control):
    def __init__(self):
        self.credenciais=[]
        self.credenciais.append( Credencial('vitor','********') )
        self.credenciais.append( Credencial('calvin','*') )
        
    def validarCredenciais(self,credencial):
        """ """
        found=False
        for c in self.credenciais:
            if(credencial.utilizador==c.utilizador and credencial.password==c.password):
                found=True
                
        if found:
            print('Credenciais válidas')
            return True            
        else:
            print('Credenciais inválidas')
            return False

class ControloCotacoes(Control):
    def __init__(self):
        """ """
        self.cotacoes=[]
        self.cotacoes.append(Cotacao('YHOO',1,'2016-01-02'))
        self.cotacoes.append(Cotacao('CSCO',1,'2016-01-02'))
        self.cotacoes.append(Cotacao('YHOO',2,'2016-01-03'))
        self.cotacoes.append(Cotacao('CSCO',2,'2016-01-03'))
        
    def obterNomesAccoes(self):
        """ """
        accoes=[]
        for c in self.cotacoes:
            if c.nome not in accoes:
                accoes.append(c.nome)
        return accoes
    
    def obterCotacoesParaAccao(self,accao):
        """ """
        cotacoesPorAccao=[]
        for c in self.cotacoes:
            if c.nome == accao:
                cotacoesPorAccao.append(c)
        return cotacoesPorAccao

class ControloMenus(Control):
    def __init__(self):
        """ """
        self.menu=Menu('Menu')
        self.menu.adicionarOpcao(Opcao('Cotações','cotacoes'))
        self.menu.adicionarOpcao(Opcao('Análises','analises'))
        self.menu.adicionarOpcao(Opcao('Sair','sair'))
        
    def getMenu(self):    
        """ """
        return self.menu
    
    def obterOpcaoPorNome(self,nomeOpcao):
        """ """
        selOpcao=None
        for o in self.menu.getOpcoes():
            if o.nome==nomeOpcao:
                selOpcao=o
        return selOpcao
        
class UI(Boundary):
    """ Lembrar de SSD System Sequence Diagram/Black Box"""
    def __init__(self):
        """ """
        self.controloMenus = ControloMenus()
        self.controloCredencial = ControloCredencial()
        self.controloCotacoes = ControloCotacoes()
        
    def pedirCredenciais(self):
        """ """
        print('Insira as suas credenciais')
        print('Utilizador:')
        utilizador = input()
        print('Password:')
        password = input()
        return Credencial(utilizador,password)   
    
    def validarCredenciais(self,credencial):
        """ """
        return self.controloCredencial.validarCredenciais(credencial)
        
    def mostrarMenu(self):
        for opcao in self.controloMenus.getMenu().getOpcoes():
            print(' %s'%(opcao.nome))
        opcao=input()
        
        selOpcao=self.controloMenus.obterOpcaoPorNome(opcao)
        mapa={'cotacoes':self.cotacoes,'analises':self.analises,'sair':self.sair}
        # define referencia de metodo conforme o nome de callback
        selOpcao.callback = mapa[selOpcao.callback]
        return selOpcao
    
    def cotacoes(self):
        print('Menu Cotações')

        for nomeAccao in self.controloCotacoes.obterNomesAccoes(): 
            print(nomeAccao)
            
        print('Escolha a cotação')
        cotacao=input()
        for c in self.controloCotacoes.obterCotacoesParaAccao(cotacao):
            print(c)
        
    def analises(self):
        print('Menu Análises')
    
    def sair(self):
        exit(0)
    
if __name__=='__main__':
    ui = UI()
    credencial = ui.pedirCredenciais()
    resultado = ui.validarCredenciais(credencial)
    
    if resultado==True:
        opcao = ui.mostrarMenu()
        opcao.callback()
        
}}}

== SOLID ==
 * https://en.wikipedia.org/wiki/SOLID

{{{
Single responsibility principle - a class should have only a single responsibility
Open/closed principle  - open for extension, but closed for modification. Decorator pattern add new responsibilities, behavior.
Liskov substitution principle  - design by contract using interfaces.
Interface segregation principle  - "many client-specific interfaces are better than one general-purpose interface."
Dependency inversion principle  -  depend upon abstractions (abstract classes or interfaces) not concrete stuff
}}}


== Software design patterns ==
 * https://en.wikipedia.org/wiki/Software_design_pattern
{{{
Singleton  - Ensure a class has only one instance, and provide a global point of access to it
Decorator - Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality. (SOLID O principle, open for extension closed for modification
Iterator - Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. next() method. IEnumerable in Csharp
Memento	 - capture and externalize an object's internal state allowing the object to be restored to this state later. persist state and restore later.
Observer or Publish/subscribe - Define a one-to-many dependency between objects where a state change in one object results in all its dependents being notified and updated automatically. attach() notify() update()
Strategy - Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. sorting algorhitms, hide used algorithm quicksort 
}}}