Flusso di lavoro sviluppo software

di il
12 risposte

Flusso di lavoro sviluppo software

Ho acquistato su Udemy un corso per imparare a sviluppare un e-commerce. Il corso è questo https://www.youtube.com/watch?v=cnqi91ugnVQ&list=PL2Q8rFbm-4ruTcZY39MNOsEu4p76HQ5VX&index=1&t=24s (su YouTube si trova la parte gratuita).
Sono arrivato alla parte della creazione delle repository.
Visto che prima abbiamo sviluppato la parte Model/Controller/View, poi abbiamo creato i servizi con le relative interfacce e ora siamo alle repositori e ad ogni fase alcuni comandi sono stati spostati da una parte all'altra, mi chiedevo se una volta acquisita la logica del flusso di lavoro con la pratica è sempre meglio utilizzare questo approccio, perché permette di tornare indietro alla fase precedente in caso di errori e da lì ripartire oppure si può accorciare il tempo di sviluppo creando in parallelo sia i servizi che le repository e vedere a lavoro ultimato se tutto funziona correttamente.

12 Risposte

  • Re: Flusso di lavoro sviluppo software

    Fabriziog ha scritto:


    mi chiedevo se una volta acquisita la logica del flusso di lavoro con la pratica è sempre meglio utilizzare questo approccio, perché permette di tornare indietro alla fase precedente in caso di errori e da lì ripartire oppure si può accorciare il tempo di sviluppo creando in parallelo sia i servizi che le repository e vedere a lavoro ultimato se tutto funziona correttamente.
    Puoi sviluppare tutto assieme. L'approccio del corso è funzionale a mostrare i ragionamenti logici che portano da una situazione all'altra, spiegando lo strumento da utilizzare, ma quando ne hai acquisito la padronanza, chiaramente puoi sviluppare il progetto con la sua architettura definitiva. Non è necessario tornare indietro su nulla.

    Ciao!
  • Re: Flusso di lavoro sviluppo software

    Okay, grazie. È come immaginavo.
  • Re: Flusso di lavoro sviluppo software

    Ho terminato la parte con la (il?) Repository e mi sono venute in mente un paio di domande per gli esperti.
    • Lavorando con le Repository sarebbe così sbagliato partire da esse, organizzando in seguito i servizi e infine dedicarsi ai Model, ai Controller e alle View?
    • Nel corso in esame tutte le chiavi primarie sono nominate Id e nell'interfaccia IEntityBase viene indicata una chiave primaria generica (se ho capito bene) a cui i vari Model si collegano.
       
       public interface IEntityBase
          {
              int Id { get; set; }
          }
      
      Per mia convenzione nei miei database non nomino mai la chiave primaria semplicemente Id, ma metto il nome della tabella. Per esempio la tabella Utenti ha come chiave primaria UtenteId, la tabella Clienti ClienteId e così via.
      Usando questo approccio quando vado ad inserire le varie chiavi primarie dei Model nell'interfaccia IEntityBase posso semplicemente indicarle come Id come nel corso oppure nominando in modo differente le diverse chiavi primarie devo inserire il nome esatto come ho scritto sia nel Model che nel database?
    • Questa invece è una curiosità: in tutti i tutorial che ho visto si parte sempre dal metodo Index dei vari controller, non sarebbe più logico partire dal metodo Create poiché i dati, in genere, prima non li abbiamo? (so che c'è la migration per popolare il database, ma mi sembra più logico vedere se l'inserimento di un nuovo record funziona)
  • Re: Flusso di lavoro sviluppo software

    Fabriziog ha scritto:


    Lavorando con le Repository sarebbe così sbagliato partire da esse, organizzando in seguito i servizi e infine dedicarsi ai Model, ai Controller e alle View?
    A mio avviso, non c'è un ordine prestabilito in queste cose. Magari il corso segue l'ordine che ritiene più comodo per affrontare gli argomenti, ma almeno che non venga esplicitato, puoi iniziare dal punto che vuoi.

    Fabriziog ha scritto:


    Nel corso in esame tutte le chiavi primarie sono nominate Id e nell'interfaccia IEntityBase viene indicata una chiave primaria generica (se ho capito bene) a cui i vari Model si collegano. [...]
    posso semplicemente indicarle come Id come nel corso oppure nominando in modo differente le diverse chiavi primarie devo inserire il nome esatto come ho scritto sia nel Model che nel database?
    L'importante è adottare una convenzione che sia uniforme: ad esempio, se in una tabella "User" hai usato "UserID", allora adotta la stessa convenzione anche per il resto del database, senza cambiare "abitudine".

    Il fatto di usare esplicitamente "ID" come nome potrebbe essere un requisito di alcuni ORM, tipo Entity Framework, che magari richiedono che il campo chiave si chiami in un certo modo, o che la chiave primaria sia formata da un solo campo e così via. Sono requisiti che magari vanno controllati un attimo prima di iniziare la progettazione, anche se in linea generale direi che la tua impostazione è altrettanto valida.

    In altri casi, il fatto che il campo si chiami sempre allo stesso modo, a prescindere dalla tabella, aiuta a costruire codice più generico e valido per differenti casistiche (es. via Reflection o altri strumenti analoghi), ma con la tua convenzione potrebbe essere ugualmente possibile. L'importante è sceglierne una e non cambiarla.

    Fabriziog ha scritto:


    in tutti i tutorial che ho visto si parte sempre dal metodo Index dei vari controller, non sarebbe più logico partire dal metodo Create poiché i dati, in genere, prima non li abbiamo? (so che c'è la migration per popolare il database, ma mi sembra più logico vedere se l'inserimento di un nuovo record funziona)
    Il metodo Index, se visualizza un elenco dei dati, è generalmente più intuitivo perché comporta una lettura, mentre la creazione o la modifica implicano una lettura e scrittura dei dati, magari una introduzione al concetto di Model Binding, ecc.

    Anche in questo caso comunque, puoi partire esattamente dal punto che preferisci.

    Io ad esempio parto dai modelli (es. ViewModel), poi passo al Controller e poi alla View, questo per non aver alcun punto del codice in cui debba lasciare un segnaposto perché manca una implementazione; tuttavia, nulla vieta di farlo, né di svilupparli assieme.

    Ciao!
  • Re: Flusso di lavoro sviluppo software

    Nel corso in esame tutte le chiavi primarie sono nominate Id e nell'interfaccia IEntityBase viene indicata una chiave primaria generica (se ho capito bene) a cui i vari Model si collegano.
    Normalmente io tendo a mantenere questa logica, così riesco a gestire molto più facilmente il codice generico.
    Faccio un esempio (e prendilo come tale, non come una regola di sviluppo):
    
    
    public interface IRepository<TEntity>
       where TEntity : ModelBase
    {
    
        TEntity GetById(int id);
        
        bool Update(TEntity entity);
        
        ...
    
    }
    
    
    public class UserRepository : IRepository<User>
    {
    
    	public bool Update(User user)
    	{
    	    var userToUpdate = GetById(user.Id); // Posso sfruttare il fatto che la chiave primaria si chiami ID
    	    ...
    	}
         
    }
    
    

    Ovviamente, come detto da Alka, si può ottenere la stessa cosa anche in modi diversi e con una proprietà che non abbia il nome fisso Id e/o nemmeno il tipo fisso int.
    Però così facendo è molto più comodo
  • Re: Flusso di lavoro sviluppo software

    Alka ha scritto:


    L'importante è adottare una convenzione che sia uniforme: ad esempio, se in una tabella "User" hai usato "UserID", allora adotta la stessa convenzione anche per il resto del database, senza cambiare "abitudine".

    Il fatto di usare esplicitamente "ID" come nome potrebbe essere un requisito di alcuni ORM, tipo Entity Framework, che magari richiedono che il campo chiave si chiami in un certo modo, o che la chiave primaria sia formata da un solo campo e così via. Sono requisiti che magari vanno controllati un attimo prima di iniziare la progettazione, anche se in linea generale direi che la tua impostazione è altrettanto valida.

    In altri casi, il fatto che il campo si chiami sempre allo stesso modo, a prescindere dalla tabella, aiuta a costruire codice più generico e valido per differenti casistiche (es. via Reflection o altri strumenti analoghi), ma con la tua convenzione potrebbe essere ugualmente possibile. L'importante è sceglierne una e non cambiarla.
    Tutto chiaro, ma non ho capito se l'interfaccia IEntityBase, indicando nelle chiavi primarie il nome delle tabelle debba essere così:
    
    public interface IEntityBase
        {
            int ActorId { get; set; } //Chiave primaria della tabella Actors
            int ProducerId { get; set; } //Chiave primaria della tabella Producers
            int MovieId { get; set; } //Chiave primaria della tabella Movies
        }
    
    Oppure si può continuare a scrivere così:
    
    public interface IEntityBase
        {
            int Id { get; set; }
        }
    
  • Re: Flusso di lavoro sviluppo software

    Fabriziog ha scritto:


    Tutto chiaro, ma non ho capito se l'interfaccia IEntityBase, indicando nelle chiavi primarie il nome delle tabelle debba essere così [...] Oppure si può continuare a scrivere così [...]
    Questa interfaccia IEntityBase come viene usata nel resto del codice?
    Si tratta di una interfaccia richiesta da qualche framework oppure l'hai introdotta tu per qualche motivo?
  • Re: Flusso di lavoro sviluppo software

    Ho seguito il corso. Dopo aver creato i servizi che si collegavano ai vari Model abbiamo creato la BaseRepository e abbiamo trasferito alcune funzionalità dai servizi (classi e interfacce), appunto, alla BaseRepository.
    In pratica, per quello che ho capito, i servizi hanno solo funzione di collegamento fra la BaseRepository (e relative interfacce) e i Model.

    Per rispondere alla tua domanda sono state create due interfacce pubbliche IEntityBase (che racchiude le chiavi primarie) e IEntityBaseRepository che elenca i metodi generici ai quali i vari Controller si collegheranno. E la classe EntityBaseRepository che - semplifico - contiene i metodi che lavorano insieme ai Controller (così ho capito) e alla classe NomeDbContext (nel mio caso AppDbContext.

    L'autore del corso ha pubblicato su GitHub (cosa molto interessante perché mi permette di vedere il codice con più calma e senza gli errori che commetto seguendo online) il codice completo e non sono previste aggiunte dopo questo punto. Quindi, non sono previste implementazioni successiva per la Repository.
  • Re: Flusso di lavoro sviluppo software

    Fabriziog ha scritto:


    Per rispondere alla tua domanda sono state create due interfacce pubbliche IEntityBase (che racchiude le chiavi primarie) e IEntityBaseRepository che elenca i metodi generici ai quali i vari Controller si collegheranno. E la classe EntityBaseRepository che - semplifico - contiene i metodi che lavorano insieme ai Controller (così ho capito) e alla classe NomeDbContext (nel mio caso AppDbContext.
    Ok, quindi data questa premessa, chiediamoci: il fatto di usare "Id" oppure "TabellaId" per il nome del campo della chiave, cambia qualcosa ai fini del funzionamento del progetto attuale?

    Se sì, allora significa che ci sono convenzioni basate sull'uso del campo con nome "Id".

    Altrimenti puoi usare il nome che vuoi, ma puoi anche eventualmente modificare l'implementazione iniziale per estenderla alle tue convenzioni.

    Non ci sono soluzioni scolpite nella pietra. L'importante è apprendere i concetti chiave e il ruolo di ogni elemento che viene inserito nel progetto, oltre al modello generale e alle interazioni/legami tra le varie classi e interfacce, poi si fanno le modifiche che si ritengono necessarie per integrare nuove funzionalità, modificarne le convenzioni, ecc.

    Stiamo parlando un pochino del "sesso degli angeli", credo.
  • Re: Flusso di lavoro sviluppo software

    Okay. Non avendo dimestichezza mi era venuto il dubbio.
  • Re: Flusso di lavoro sviluppo software

    Ho terminato la parte CRUD, ma avrei delle domande perché alcuni passaggi non mi sono chiari.
    Per ultima è stata implementata la View della tabella più importante: Movies, l'unica che conteneva delle chiavi esterne (una relazione molti a molti, due uno a molti, e una associata ad una classe enum).
    Per questa tabella è stato creato un ViewModel. Ho visto a che serve un ViewModel e, se non ho capito male, aiuta a velocizzare la visualizzazione in caso di tabelle complesse.
    Ora, siccome questa è l'unica tabella complessa di tutto il corso, mi chiedo come riesco a valutare la complessità di una tabella. Basta che ci sia una chiave esterna? Ne servono almeno due? Purtroppo il corso non lo dice. E dalle mie ricerche in rete non sono riuscito a scoprirlo.

    Seconda cosa. Per questa tabella è stato seguito un approccio differente rispetto a quelli seguiti finora.
    Mentre per una tabella semplice come quella Actors lo ActorsService aveva solo questo codice:
    
    public class ActorsService : EntityBaseRepository<Actor>, IActorService
        {       
            public ActorsService(AppDbContext context) : base(context) { }
        }
    
    Per quanto riguarda la tabella Movies lo MoviesService ha diversi metodi in base all'azione del controller. Qui di seguito quello per il Create:
    
    public async Task AddNewMovieAsync(NewMovieVM data)
            {
                var newMovie = new Movie()
                {
                    Name = data.Name,
                    Description = data.Description,
                    Price = data.Price,
                    ImageUrl = data.ImageUrl,
                    CinemaId = data.CinemaId,
                    StartDate = data.StartDate,
                    EndDate = data.EndDate,
                    MovieCategory = data.MovieCategory,
                    ProducerId = data.ProducerId,
                };
    
                await _context.AddAsync(newMovie);
                await _context.SaveChangesAsync();
    
                //Add Movie Actors
                foreach (var actorId in data.ActorIds)
                {
                    var newMovieActor = new Actor_Movie()
                    {
                        MovieId = newMovie.Id,
                        ActorId = actorId,
                    };
    
                    await _context.Actors_Movies.AddAsync(newMovieActor);
                }
                await _context.SaveChangesAsync();
            }
    
    E poiché il corso non lo spiega (o forse sono io che non l'ho capito) non riesco a capire se questo è un approccio differente oppure in caso di presenza di ViewModel questo è il codice da utilizzare.
  • Re: Flusso di lavoro sviluppo software

    Fabriziog ha scritto:


    Ho visto a che serve un ViewModel e, se non ho capito male, aiuta a velocizzare la visualizzazione in caso di tabelle complesse.
    La finalità dei ViewModel è quello di agevolare il passaggio di dati dal Controller alla View, creando un apposito contenitore nel quale immagazzinare in modo strutturato e congeniale le informazioni che la vista dovrà poi andare a prendere per riportarle all'interno di una pagina, di un file o altro.

    Un ViewModel andrebbe creato ogni volta che può far comodo, soprattutto quando può evitare o ridurre ulteriormente il codice inserito nella View, perché la vista tendenzialmente è l'unico elemento non testabile in modo automatizzato del progetto, quindi dovrebbe contenere solo codice con complessità 1 (es. niente if(), niente switch(), ecc.).

    Quindi, non fare caso alla complessità della tabella, ma valuta il codice della vista e sposta nel ViewModel tutto il possibile.

    Ad esempio, supponiamo che la vista debba riportare la stessa lista di elementi ma ordinata in due modi diversi: crea un ViewModel da inizializzare con gli elementi di partenza e aggiungi due metodi che ti restituiscano gli stessi elementi con i diversi ordinamenti applicati da mostrare nella pagina. Oppure, mettiamo che tu debba applicare una formattazione particolare ad alcuni valori di una vista specifica: invece di ridondare il codice o scriverlo nella vista, inseriscilo nel ViewModel e richiamalo dalla vista stessa.

    E' chiaro che se le funzionalità inserite nel ViewModel possono essere utili altrove (es. formattazione di date con un certo formato o altre feature condivisibili), allora dovrebbero stare invece in un altro contenitore, o in una Class Library dedicata, in modo da poter essere accessibili ovunque serva.

    Fabriziog ha scritto:


    Ora, siccome questa è l'unica tabella complessa di tutto il corso, mi chiedo come riesco a valutare la complessità di una tabella.
    E' semplice: non usare quel criterio. Io ad esempio il ViewModel lo creo sempre: in questo modo, non ho mai ostacoli futuri a qualsiasi necessità di introdurre al suo interno nuovi dati e/o funzionalità, sollevandomi dalla necessità di andare a modificare in seguito sia il Controller che la View.

    Fabriziog ha scritto:


    Per questa tabella è stato seguito un approccio differente rispetto a quelli seguiti finora.
    [...]
    E poiché il corso non lo spiega (o forse sono io che non l'ho capito) non riesco a capire se questo è un approccio differente oppure in caso di presenza di ViewModel questo è il codice da utilizzare.
    Più che un approccio differente, se ho capito bene il codice, mi pare solo che ci si trovi in presenza di uno scenario dove l'operazione di riferimento debba inserire contestualmente più record su tabelle correlate, da cui la parte di codice aggiuntiva (o più complessa, all'apparenza).

    La logica da implementare dipende dalla quantità e dal tipo di dati da trattare. Non dipende dal ViewModel, sia perché il ViewModel potrebbe essere creato in seguito, sia perché le due parti sono disgiunte: la logica del Controller o del Model, a seconda di dove la si vuole collocare, gestiscono la "business logic" del sistema, mentre il ViewModel fa solo da aggregatore e da supporto al veicolare alcune informazioni verso le viste, o dalle viste (se prendiamo in considerazione anche il meccanismo di Model Binding, ossia della capacità di ASP.NET di compilare un ViewModel con i dati provenienti da un <form>).

    Ciao!
Devi accedere o registrarti per scrivere nel forum
12 risposte