Jump to content
php.lv forumi
Sign in to follow this  
labaiss

kurš ir labākais CMS

Recommended Posts

Un atkārtošos... parādi Man, wintermute, reālu "framework'u", kad dara visu tā, kā Tev patīk? Nu pēc Wikipedia's definīcijām. Un tad, lūdzu, pastāsti ieguvumus tam. Ātrdarbība? Mazāk kods? Nedomāju viss.

Share this post


Link to post
Share on other sites

Kas tas par murgu? Jebkuru darbu var sadalīt smalkāk - jebkuru funkcionalitāti var sadalīt smalkāk.

Tāpēc tāds jēdziens kā viena funkcija ir absurds.

Metodei jāpilda tāda funkcionalitēte, kuru loģiskā veidā var atdalīt no pārējā un katrs gadījums ir individuāls.

Pietam, viena metode var saturēt algoritmu, kurš izmanto vairākas citas metodes - bez tā nav iespējams iztikt.

Pēc tavas šīs filozofijas, nav nemaz iespējams būvēt normālus aplikācijas abstrakcijas slāņus.

 

gan jau Clean Code mudinātais tīrums

 

bet nu tur tas vairāk bija par to, ka funkcijai ir jādara viena loģiska lieta nevis aprēķina 3 mainīgo summu, pēc tam 3 neatkarīgu mainīgo reizinājumu un vēl 3 reizes izvada Hello World

Share this post


Link to post
Share on other sites

gan jau Clean Code mudinātais tīrums

 

bet nu tur tas vairāk bija par to, ka funkcijai ir jādara viena loģiska lieta nevis aprēķina 3 mainīgo summu, pēc tam 3 neatkarīgu mainīgo reizinājumu un vēl 3 reizes izvada Hello World

Tas cik attiecīgā papildus funkcionalitāte ir nesaistīta ar metodes pamatfunckionalitāti ir diskutabls jautājums. Piemēram, piemērs ar lietotāju, kurš pērk preci. Lietotājam ir metode buy(), kura atņems lietotājam naudu, ja preci varēs nopirkt. Bet, piemēram, mēs gribam drošības pēc darbības ar naudām vēlamies saglabāt, tāpēc logojam tās. Lai gan pati logošanas darbība ir diezgan nesaistīta, to liksim buy metodē iekšā, nev aiz katras $user->buy().

 

<?php
class Product{
 public
   $price;
}
class User{
 public 
   $money;
 public function buy(Product $product){
   if ($product->price <= $this->money){
     $this->money-=$product->price;
     //šeit liks transakcijas logošanu
   } else {
     throw new Exception('Not enough money');
   }
 }
 public echoMoney(){
   echo 'Users money: '.$this->money.' <br />';
 }
}
$product=new Product();
$product->price=100;
$user=new User();
$user->money=50;

$user->echoMoney();
try{
 $user->buy($product);
 //šeit vaētu likt tranakcijas logošanu, bet tas nebūtu tas labākais variants.
}catch(Exception $e){
 echo 'Not succed because: '.$e->getMessage().'<br />';  
}
$user->echoMoney();

Share this post


Link to post
Share on other sites

būtībā vienkārši nevajaga krist galējībās, jo taisot lielas metodes ar daudziem tai uzticētiem uzdevumiem gala rezultātā daudzkārt sanākt liels magic push button's, kuru izpildot viss strādā, bet neviens skaidri nezina kāpēc

Share this post


Link to post
Share on other sites

Piemērs, kur tu šo praksi nevari apiet.

Datubāze. Tev ir divi objekti, kuri darbojas ar db. Nu netaisīsi tu katram savu konekciju tā viena iemesla dēļ, ka tad tu nevarēsi nodrošināt transakcijas.

Nu tad tu katram no tiem objektiem konstruktorā padod vienu un to pašu DB klases objektu, kaut vai pliku PDO instanci.

$db = new PDO('sqlite::memory:');
$foo = new Foo( $db );
$bar = new Bar( $db );

$bar->do_stuff();

$foo->set_blah('hitchhiker');
echo $foo->get_towel();

Kur tieši tev rodas problēma ?

Ja tev kādā objektā vajag Factory'u, tad to to padod konstruktorā.

Un ja tas objekts izmanto Cache'u, tad arī tas tiek padots konstruktorā.

 

Ja tiek mainīt nosaukums kolonai, tad arī aplikācijā ar plikiem SQL, tev būs jāmaina visi SQL, kur izmanto šo kollonu. Tāda ir dzīve.

Bez tam izmantojot ORM, kuros kollonas definē modeļa definīcijā, db tabulas pa tiešu vispār neaiztiek, tā vietā to dara tūļi, kuri modeļa definīciju pārnes uz db.

Tiešām ? Ak tad modelis nav saistīts ar datubāzi. Tad tu gribi man teikt, ka es varu nemainot pašu modeli glabāt un saņemt datus no XML faila vai kāda web-servisa ?

Un par kolonām .. emm .. modelim nav nekāda sakara ar to tu fiziski glabā datus. Modelis !== ORM. Blame RoR.

( .. gandrīz vai jādomā, ka vienīgā DB abstrakcijas arhitektūras pattern's, kuru tu zini, ir active-record )

 

 

Par vienvirziena datu plūsmu, no modeļa, tikai uz view-u un no kontrolera tikai uz modeli.

Praksē tas nav iespējams, jo kontrolerim gandrīz vienmēr būs nepieciešami dati no modeļa, lai veiktu tālākās darbības.

Piemēram, tu nospied pogu pirkt. Kontrolerim ir jāpārbauda vai lietotājam pietiek nauda (no user modeļa), jāpārbauda vai noliktavā ir prece (no storage modeļa), utt. un tikai tad, kad ir saņemti dati no vairākiem mopdeļiem, kontroleris var tālāk izlemt kādas darbības un izmaiņas veikt citos kontroleros un kādu view izsaukt.

Ko darīt ar pirkumu, ja lietotājam nav naudas, izlemj modelis.

Kā attēlot lietotājam, ka viņam nav naudas, izlemj view.

Kontrolieris vienkārši padod lietotāja ievaddatus un modeli(-ļus) pie view.

 

 

 

Kas tas par murgu? Jebkuru darbu var sadalīt smalkāk - jebkuru funkcionalitāti var sadalīt smalkāk.

Tāpēc tāds jēdziens kā viena funkcija ir absurds.

Metodei jāpilda tāda funkcionalitēte, kuru loģiskā veidā var atdalīt no pārējā un katrs gadījums ir individuāls.

Pietam, viena metode var saturēt algoritmu, kurš izmanto vairākas citas metodes - bez tā nav iespējams iztikt.

Pēc tavas šīs filozofijas, nav nemaz iespējams būvēt normālus aplikācijas abstrakcijas slāņus.

Šķiet vakar pa nakti neizdevās normāli domu noformulēt :

katra metode atbild par vienu noteiktu, viegli noformolējamu darbību.

class TaskManager
{
   function complete_task( $task , $user )
   {
       $task->mark_completed( $user );
       if ( $this->has_more_tasks( $user ) )
       {
           $new_task = $this->get_next_task( $user );
           $this->assign_task( $new_task , $user )
       }
   }
}

Kodā metodei ir viens pienākums ( uzdevums , funkcija ) un tev nevajag pusstundu pērties pa kodu,

lai saprastu ko tā metode dara.

 

 

 

 

Un ko darīsi, ja būs int parametrs ar iespējamām 5 vērtībām? Taisīsi 5 funkcijas.

Pietiek murgot. Sāc domāt.

Ja tev ir funkcija, kas dara 5 dažādas lietas, atkarībā no kaut kāda mistiska flag'a vērtības,

tad tev pilnīgi noteikti būtu jābūt 5ām funkcijām.

Un ja tev klasē it divas+ funkcijas, kam tādu flag'u vajag,

tad optimālāk būtu izmantot polimorfismu un sadalīt to objektu pa 5ciem jauniem objektiem,

kuri implementē vienu un to pašu interfeisu

Share this post


Link to post
Share on other sites

Kur tieši tev rodas problēma ?

Ja tev kādā objektā vajag Factory'u, tad to to padod konstruktorā.

Un ja tas objekts izmanto Cache'u, tad arī tas tiek padots konstruktorā.

Problēma rodas tur, ka pie katra objekta veidošansa tev viņam būs jānodod daudz parametru.

Nu neērti un nepārskatāmi ir katram modelim nodod db, memcahced, utt. instances.

 

Kāda jēga no lieka rakstīt:

$db=DBFactory::dod_shurp_db_instani();
$memcahced=DBFactory::dod_shurp_memcahced_instanci();
$user = new User($db,$memcahced,123);

 

Lai tā vietā rakstītu:

$user=User(123);

un modeļi db piekļūs caur globāli pieejamu factory.

 

 

Tiešām ? Ak tad modelis nav saistīts ar datubāzi.

Parādi kurā vietā es tā rakstīju?

 

Tad tu gribi man teikt, ka es varu nemainot pašu modeli glabāt un saņemt datus no XML faila vai kāda web-servisa ?

Patiesībā jā. Ja tev datu modeļa pamatruktūra ir būvēta kā Strategy paterns un tu vari CRUD algoritmus nodot kā atsevišķas strategy klases. Kāpēc ne?

Taču jāskatās vai visas nepieciešamo modeļa funkcionalitāte spēs nodrošināt katrs no algoritmiem: mysql, xml fails, web-serviss.

 

Un par kolonām .. emm .. modelim nav nekāda sakara ar to tu fiziski glabā datus. Modelis !== ORM. Blame RoR.

Modeļi var būt būvēti uz dažādiem paterniem un katrs no tiem strādās savādāk. Modelis nav ORM, bet ORM ir modelis.

Pie tam veidojot modeli, ir spēcīgi jāņem vērā arī tas, kā fiziski glabās datus, jo vienā veidā modeli varēs uzbūvēt, bet citā veidā teorētiski nebūs iespējams veikt kaut kādu funkcionalitāti, kā pirmajā gadījumā, un modeli nebūs iespējams uzbūvēt.

 

 

Kā attēlot lietotājam, ka viņam nav naudas, izlemj view.

Nevienmēr, tikpat labi tas var būt jāizlemj kontrolerim. Pat šādā elmentārā situācijā, paziņojumu, ka nav naudas, var veidot kā atsevišķu view-u

Bet ko darīsi, ka modeļa datu apstrādē ieviesīsies kļūda un vajadzēs padot citu view-u (kļūdu paziņojumu)? Tas jāizlemj kontrolerim.

 

 

Kontrolieris vienkārši padod lietotāja ievaddatus un modeli(-ļus) pie view.

Nu nav tā.

Kontrolerim ir jāsaņem un jāapstrādā dati no modeļa:

- Ja lietotājs nav ielogojies, mainam view-u vai redirektojam.

- Ja lietotājs nav pieeja sadaļai, mainam view-u.

- Tāpat apskatot konkrēto lapu, mēs varam gribēt skaitīt lapas sadaļas unikālos apskatījumus. Šādā gadījumā kontrolerim vajadzēs iegūt datus par lietotāju, par konkrēto sadaļu, apstrādāt un nosūtīt šos datus apskatījumu modelim.

 

 

Ja tev ir funkcija, kas dara 5 dažādas lietas, atkarībā no kaut kāda mistiska flag'a vērtības,

tad tev pilnīgi noteikti būtu jābūt 5ām funkcijām.

Un ja tev klasē it divas+ funkcijas, kam tādu flag'u vajag,

tad optimālāk būtu izmantot polimorfismu un sadalīt to objektu pa 5ciem jauniem objektiem,

kuri implementē vienu un to pašu interfeisu

Tam es piekrītu, bet tu iepriekš strikti pateici, ka, ja ir boolean parametrs, tad kaut kas nav pareizi.

Ne vienmēr boolean parametrs atdala divas funkcionalitātes.

Share this post


Link to post
Share on other sites

Par kontroliera būtību es piekrītu "Codez" - kaut, gan lasot Jūsu dialogu - es saprotu, ka šeit labāk nelīst pa vidu un nejaukties:

iemesls - nēsmu Jūsu svara kategorijā.

 

P.S. Tā kā viss drīzāk mans komentārs nav vērā ņemams.

Share this post


Link to post
Share on other sites

Problēma rodas tur, ka pie katra objekta veidošansa tev viņam būs jānodod daudz parametru.

Nu neērti un nepārskatāmi ir katram modelim nodod db, memcahced, utt. instances.

 

Kāda jēga no lieka rakstīt:

$db=DBFactory::dod_shurp_db_instani();
$memcahced=DBFactory::dod_shurp_memcahced_instanci();
$user = new User($db,$memcahced,123);

 

Lai tā vietā rakstītu:

$user=User(123);

un modeļi db piekļūs caur globāli pieejamu factory.

 

Kurš tev teica ka tā vajag rakstīt ?

 

Tas ko es parakstīju izskatītos apmēram šitā :

 

//--------------------------------------
// fails  userfactory.php

class UserFactory implements UserBuilder
{
  protected $_db;
  protected $_cache;
  protected $_id = null ;

  public function __construct( PDO $db , Cache $cache = null )
  {
     $this->_db = $db;
     $this->_cache = $cache;
  }
  public function set_id( $id )
  {
     $this->_id( $id )
  }
  public function build()
  {
      return new User( $this->_id , $this->_db , $this->_cache );
      // tas , vai ID tiek resetot''s vai nē ir gaumes (un dokumentācijas) jautājums
  }

}

//--------------------------------------
// fails bootstrap.php

$db = new PDO('sqlite::memory:');
$mc = new Memcached('cache');
$mc->addServers(array(
    array('mc1.example.com',11211),
    array('mc2.example.com',11211)
));

$factory = new UserFactory( $db , $mc );

$foo = new Foo( $factory );
$foo->bar();

//--------------------------------------
// fails foo.php

class Foo
{
  protected $_factory;

  public function __construct( UserBuilder $factory )
  {
     $this->_factory = $factory;
  }
  public function bar()
  {
     $user = $this->factory->set_id(123)->build();
     /*
     $user3 = $this->factory->set_id(3243)->build();
     $Arthur = $this->factory->set_id(42)->build();
     */
  }

}

 

Tieši kur ir problēma ?

Tagad, ja tev vajag pamainīt to kādu no elementiem,

tad tev vairs nav jāpārraksta metode bar().

 

Un ja tu gribi izveidot unit-testu priekš klases Foo,

tu vari mierīgi aizstāt ar mock-objektiem DB un Cache,

vai pat visu UserFactory, ja ir luste.

 

 

 

Patiesībā jā. Ja tev datu modeļa pamatruktūra ir būvēta kā Strategy paterns un tu vari CRUD algoritmus nodot kā atsevišķas strategy klases. Kāpēc ne?

Taču jāskatās vai visas nepieciešamo modeļa funkcionalitāte spēs nodrošināt katrs no algoritmiem: mysql, xml fails, web-serviss.

 

Modeļi var būt būvēti uz dažādiem paterniem un katrs no tiem strādās savādāk. Modelis nav ORM, bet ORM ir modelis.

Pie tam veidojot modeli, ir spēcīgi jāņem vērā arī tas, kā fiziski glabās datus, jo vienā veidā modeli varēs uzbūvēt, bet citā veidā teorētiski nebūs iespējams veikt kaut kādu funkcionalitāti, kā pirmajā gadījumā, un modeli nebūs iespējams uzbūvēt.

 

Nē tā nav. Modelis atbild nevis par "datu loģiku" bet gan par "domeina biznesa loģiku".

Tam nav nekāda sakar ar to kā un kur tu tos datus glabā.

Produkta X daudzums noliktavā nav atkarīgs no tā, vai dati par to nāk no web-servisa, datubāzes vai xml.

 

Tāpēc arī ORM nav modelis. Tās ir divas pilnīgi neatkarīgas struktūras.

 

 

 

 

Nevienmēr, tikpat labi tas var būt jāizlemj kontrolerim. Pat šādā elmentārā situācijā, paziņojumu, ka nav naudas, var veidot kā atsevišķu view-u

Bet ko darīsi, ka modeļa datu apstrādē ieviesīsies kļūda un vajadzēs padot citu view-u (kļūdu paziņojumu)? Tas jāizlemj kontrolerim.

 

Nu nav tā.

Kontrolerim ir jāsaņem un jāapstrādā dati no modeļa:

- Ja lietotājs nav ielogojies, mainam view-u vai redirektojam.

- Ja lietotājs nav pieeja sadaļai, mainam view-u.

- Tāpat apskatot konkrēto lapu, mēs varam gribēt skaitīt lapas sadaļas unikālos apskatījumus. Šādā gadījumā kontrolerim vajadzēs iegūt datus par lietotāju, par konkrēto sadaļu, apstrādāt un nosūtīt šos datus apskatījumu modelim.

Liekas problēma ir faktā, ka tu ar jēdzienu View saproti kaut ko pavisam citu.

View nav "stulbs" template's, bet gan pilnvērtīga klase, kas darbojas ar vairākiem templatiem.

class DocumentView extends View implements Renderable
{
  public function render()
  {
     $factory = $this->_template-factory;
     try
     {
        $document = $this->library->get_document();
        $template = $this->get_template('main');
        $template->bind( 'title' , $document->get_title() );
        $template->bind( 'content' , $document->get_content() );
     }
     catch( AuthorizationException $e )
     {
        $template = $this->get_template('error');
        $template->bind( 'content' , 'Unauthorized access, please stop that !' );
     }

     return $template->render();
  }
}

Un kontrolierī ir rakstīt apmēram kaut kas šitāds.

class DocumentController extends Controller
{
  protected _view_name = 'DocumentView';
  protected _view = null;

  public function get_document()
  {
     $factory = $this->_model_factory;
     $library = $factory->set_class( 'Library' )->build(); // set_class() atrgriež $this

     $this->_view->set_template('main' ,  'some/location/document.tpl');
     $this->_view->set_template('error' , 'maybe/different/location/baaaaad.tpl');
     $this->_view->bind( 'library' , $library );

     $library->select_document( $this->get_param('id') );
  }

}

 

Tas ir apmēram kā es saprotu MVC triādi.

- model: atbild par biznesa loģiku

- view: atbild par prezentācijas loģiku

- controller: sasaista view are modeļiem , un padod tiem 'signalus', kuri maina view un modeļu stāvokli

 

 

Tam es piekrītu, bet tu iepriekš strikti pateici, ka, ja ir boolean parametrs, tad kaut kas nav pareizi.

Ne vienmēr boolean parametrs atdala divas funkcionalitātes.

Bet tā jau arī ir , ka booleans atdala divas funkcionalitātes.

Ja tev ir viena vērtība, tad tu dari lietu a , un ja tev ir otra vērtība,

tad tu dari lietu b ( vai arī dari gan a gan b ).

Share this post


Link to post
Share on other sites

Un atkārtošos... parādi Man, wintermute, reālu "framework'u", kad dara visu tā, kā Tev patīk? Nu pēc Wikipedia's definīcijām. Un tad, lūdzu, pastāsti ieguvumus tam. Ātrdarbība? Mazāk kods? Nedomāju viss.

Ja es atradīšu tādu , noteikti padalīšos.

 

Bet vai tev tiešām liekas, ka tādi jēdzieni kā "loose coupling" in SOLID principi,

tika izdomāti tāpēc, lai kods kļūtu lēnāks un grūtāk uzturams ?

Share this post


Link to post
Share on other sites

Tur jau tā lieta... Es nezinu. Es daru kā vairākums, bet gribu darīt kā labāk.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...