bjornposts4d-blog
def s4d(): pass
87 posts
Tumblelog van Bjorn Post voor het semester S4D.
Don't wanna be here? Send us removal request.
bjornposts4d-blog · 14 years ago
Text
Tsja, hier stond je dan vanavond. Het was wel spannend, maar toch ook fijn. Afgelopen 20 weken heb ik veel mensen enorme groeispurten zien maken, moi incluis. Ik kon één trucje heel goed (PHP), maar kan nu m'n eigen avondvullende show geven. In Rails, Django of PHP. Of Arduino en Javascript.
Ik heb ontdekt dat ik het vermogen heb om in enkele weken heel veel informatie van zo'n nieuwe taal in me op kan nemen, waar anderen veel meer moeite daarmee hebben. Ik onthoud de namen, de syntax, etc. Dat scheelt een hoop tijd, omdat je niet steeds alles moet opzoeken.
Daarnaast heb ik ontdekt dat ik het gemakkelijk vind om terug te vallen op wat ik al weet. Simpel voorbeeld; als ik wil weten hoe ik een functie kan triggeren nadat ik iets heb opgeslagen, val ik terug op wat ik weet: post_save signals in Django. Dat is wat ik wil, maar dan in Rails. Google: post_save in rails. Al bij de 5 resultaten vind ik mijn antwoord.
Wat ik lastig vond, maar volgens mij wel goed heb aangepakt; is mensen zelf laten spartelen. Gewoon aan het werk zetten en zelf laten zoeken, en er niet meteen bovenop springen en het probleem binnen twee minuten zelf oplossen. Daar leert niemand iets van, ook ik niet. Daarom heb ik vaak voor de aanpak gekozen om wel te helpen, maar dan op een meer conceptueel niveau: wat hoort waar? Waarom daar? Zo hielp ik de ander op weg, zonder ze direct het antwoord te geven.
De afgelopen vijf weken heb met goede mensen samengewerkt. We hebben veel gedaan, en ook goed werk verricht, naar mijn idee. Een mooie applicatie, bijna klaar voor oplevering. Ik denk dat we goede keuzes hebben gemaakt along the way, zeker door gebruik te maken van Git/Github.
Git heeft ons in the end veel tijd bespaart, en was daarnaast ook nog eens een heel leerzame ervaring. Zelf kende ik alleen Mercurial (hg), maar ook maar voor projectjes waar je alleen of met z'n tweeën aan werkte. Nu waren we met z'n vijven tegelijk met dezelfde repository bezig, en dat is toch wel even 'plannen' om onnodig veel merge-werk te voorkomen. Ook al gaat dat in negen van de tien gevallen automatisch.
'Met z'n allen', zo hebben we het gedaan. Thanks all!
1 note · View note
bjornposts4d-blog · 14 years ago
Text
Gisteren was onze workshop. Het programma zat stamp-- en dan ook écht stampvol, maar we hebben wel veel kunnen laten zien van Rails. Het grootste nadeel van Rails is dat je relatief veel voorbereidingswerk hebt, zeker voor zo'n simpele applicatie als bij de workshop. Ik hoop dat mensen hebben begrepen dat die voorbereiding zich naar mate de applicatie groeit, steeds sneller terugbetaald. Misschien hebben we dat niet genoeg benadrukt, en dat zou wel eens nadelig kunnen zijn voor Rails' imago.
Ik ben zelf vooral blij dat we lang niet iedereen zijn verloren onderweg, ik kan me namelijk voorstellen dat we soms wel heel hard gingen. Helemaal op het gebied van controllers. Al was dat iets waar we niet de nadruk op wilde leggen. We wilden namelijk vooral aandacht geven aan templates en models. Ik denk dat dat goed is gelukt.
Daan heeft goed uitgelegd hoe je relaties tussen data kunt leggen, en hoe je die kunt gebruiken in je code. En welke voordelen dat heeft. Roy heeft op zijn beurt veel aandacht besteed aan templates. Elbert heeft veel verteld over gems (en de kracht daarvan) en Niels en ik hebben de laatste eindjes aan elkaar geknoopt.
Ronald vatte de workshop goed samen: "In de laatste 30-45 minuten viel alles op zijn plek". En dat was ook zo. Veel voorbereiding en op het eind komt alles ineens bij elkaar.
Rails is nog steeds niet mijn grootste vriend, maar ook zeker geen vijand meer. De Ruby syntax is niet mijn ding, maar kan er ondertussen wel mee overweg. Rails' ActiveRecord library is een geschenk, en werkt heerlijk. Idem ditto voor de overdaad aan beschikbare gems (en management daarvan via Gemfile). Ook de Ruby Make tools (rake) zijn lekker. Minder vind ik dat hele scaffolding verhaal, wat snel grote beveiligingsgaten in je applicatie kan geven als je niet oppast.
17 notes · View notes
bjornposts4d-blog · 14 years ago
Photo
Tumblr media
0 notes
bjornposts4d-blog · 14 years ago
Text
Vandaag neem ik je mee op reis door onze Gemfile. De Gemfile is een bestand waar je al je project dependencies in stopt, je kunt daarbij denken aan Typus, een gem die wij gebruiken om onze admin interface te genereren. Deze wordt standaard niet meegeleverd met Rails, maar dankzij de Gemfile kunnen we deze toch gemakkelijk gebruiken.
Een Gemfile is gewoon platte tekst, en bevat allemaal regeltjes als:
gem "rails", "3.0.3"
De eerste parameter geeft de naam van de gem aan, de tweede de versie. Als je geen versie opgeeft, pakt hij de laatste die hij kan vinden. Onze Gemfile ziet er als volgt uit, en ik zal per regel even uitleggen waarvoor wij de betreffende gem gebruiken.
source 'http://rubygems.org' gem 'rails', '3.0.3' # Paperclip gebruiken wij om fileuploads af te handelen. Deze plugin # zorgt ervoor dat de bestanden worden geverifieerd en verkleind # door middel van imagemagick. In productie zorgt deze gem er # daarnaast ook voor dat de uploads terecht komen in onze S3 bucket. # # ∞ https://github.com/thoughtbot/paperclip gem 'paperclip' # has_scope is een gem die controller filters koppelt aan resource # scopes. Dat klinkt lastiger dan het is. Op je model maak je een # named scope, en op je controller geef je vervolgens aan dat de # controller een scope heeft. # # ∞ https://github.com/plataformatec/has_scope gem 'has_scope' # will_paginate zorgt ervoor dat onze pagina's niet oneindig lang # worden. Met een handige helper genereert hij ook direct vorige/ # volgende pagina links. # # ∞ https://github.com/mislav/will_paginate gem 'will_paginate' # meta_where is query syntax on steriods. Tenminste, zo omschrijven # ze het zelf. Waar het in de praktijk op neer komt is dat je geen # SQL fragments meer in je code hoeft te stoppen: # where(‘name LIKE ?’, ’%hoi%’) wordt where(:name =~ 'hoi'). Nice! # # ∞ https://github.com/ernie/meta_where gem 'meta_where' # Typus is een gem die een prachtige backend interface voor je app # maakt op basis van je models. Je hoeft dus maar weinig zelf in # te stellen. Hoewel hij nog lang niet zo flexibel is als Django's # Admin interface, is het nog steeds minder werk om dit te inte- # greren dan om het zelf te schrijven. # # ∞ https://github.com/fesplugas/typus gem 'typus' # Devise is mijn grote vriend als het gaat om authentication en # authorisation. Deze gem neemt namelijk alles uit je handen mbt. # user registration: aanmelden, e-mail confirmation, rechten, etc. # Het enige dat jij moet doen is even aangeven welke actions in je # controller alleen toegankelijk zijn voor mensen met een account. # # ∞ https://github.com/plataformatec/devise gem 'devise', :git => 'git://github.com/plataformatec/devise.git' # De Googlecharts gem gebruiken we in de admin interface om de # grafiekjes te genereren. Het makkelijke aan de library is is dat # hij de juiste URL genereert op basis van wat hashes. Scheelt een # hoop werk, en houd je code lekker overzichtelijk. # # ∞ https://github.com/mattetti/googlecharts gem 'googlecharts' # active_link_to is een vervanger voor de welbekende link_to helper. # De helper is enorm simpel, en zorgt ervoor dat de href-tag een # class="active" krijgt wanneer de huidige URL hetzelfde is als de # URL die hij genereert. Hendig! # # ∞ https://github.com/theworkinggroup/active_link_to gem 'active_link_to' # De aws-s3 gem is een Ruby interface voor het S3 storage platform # van Amazon. Deze gem wordt gebruikt door paperclip. # # ∞ https://github.com/marcel/aws-s3 gem 'aws-s3'
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Vandaag zijn we vooral bezig geweest met de kersjes op onze taart. Voor mij betekende dat dat ik me heb bezig gehouden met de ActionMailers, Model callbacks en de ActiveRecord Dirty. Dit is mijn team om ervoor te zorgen dat een orderbevestiging verstuurd kan worden nadat de bestelling is ontvangen, en om mailtjes te versturen als de status van een order veranderd.
Een korte introductie:
Het ActionMailer��framework in Rails is verantwoordelijk voor het maken en versturen van e-mails. In mijn team is hij daar dus ook verantwoordelijk voor.
De Model callbacks, specifieker: after_save en after_create, zijn de jongens die ervoor zorgen dat de mailers aangeroepen worden.
Met ActiveRecord Dirty kun je gemakkelijk zien of een waarde in de tabel veranderd is. Deze ga ik gebruiken om te voorkomen dat er altijd statusmails worden verstuurd nadat de order is opgeslagen.
Ik ben begonnen van het opzetten van de Mailer. Ik heb een OrderMailer gemaakt, met daarin twee functies. Een thank_you functie, deze verstuurd de 'bedankt voor je bestelling'-mail, en een status_update functie, deze verstuurd een bericht dat de status van een bestelling is veranderd. Beide mails worden verstuurd naar degene die de order heeft geplaatst. Zo ziet de code van de mailer eruit:
class OrderMailer < ActionMailer::Base default :from => "[email protected]" def thank_you(order) @order = order mail(:to => @order.user.email, :subject => "Thank you for your order") end def status_update(order) @order = order mail(:to => @order.user.email, :subject => "About your order #{@order.id}") end end
Bij de mailer horen ook enkele views, thank_you.text.erb en status_update.text.erb. Deze bevatten het daadwerkelijke bericht en werken hetzelfde als een gewoon template.
Daarna ben ik verder gegaan met het maken van de model callbacks:
class Order < ActiveRecord::Base # after_create wordt aangeroepen nadat het record is aangemaakt. # we geven als parameter :send_confirmation mee, een referentie # naar de private send_confirmation functie. after_create :send_confirmation # after_save wordt aangeroepen nadat een record is opgeslagen after_save :status_update private def send_confirmation() OrderMailer.thank_you(self).deliver # een callback moet altijd true teruggeven anders # wordt de callback-chain verbroken. true end def status_update() # ActiveRecord Dirty: order_status_changed? geeft true # terug wanneer waarde is veranderd. Anders false. if self.order_status_changed? OrderMailer.status_update(self).deliver end true end end
Daarna was het een kwestie van testen. Gelukkig krijg je in de development environment niet écht de mailtjes toegestuurd, maar zie je het bericht gewoon in je console. Dat voorkomt dat je spamfilter de mailtjes afvangt, of dat je lang moet wachten totdat het mailtje zichtbaar is.
Ik ben vooral onder de indruk van ActiveRecord Dirty, volgens mij kan dit niet met Django's ORM (al heb ik er niet naar gezocht). Maar ook de ActionMailer werkt erg prettig, al is deze qua features een stuk minder spannend; het werkt gewoon.
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Gister en vandaag ben ik vooral bezig geweest met het uitrollen van onze webshop op Heroku:
Heroku is an online Rack (and by extension, Ruby on Rails) cloud PaaS (Platform as a Service) run by a San Francisco, California based company with the same name. As one of the very first cloud platform as a service providers, Heroku has been in development since June 2007 and the company reports over 105,000 applications running on its service.
Dat klinkt heel spannend, maar eigenlijk hosten ze 'gewoon' je applicatie. En het werkt gewoon als een git repository. Da's handig.
Ik ben begonnen met het maken van mijn app op Heroku. Wat dat eigenlijk inhoud, is dat Heroku wat mappen aanmaakt op hun server, en jou toegang daartoe geeft door middel van een git repository. Zo'n git repository is erg gemakkelijk, want daardoor kun je je wijzigingen gewoon richting Heroku pushen, en hoef je niet steeds je complete website te updaten.
Je app deployen is dus niet meer werk dan een simpele git push heroku master.
Vervolgens krijg je een response van Heroku in de vorm van:
Counting objects: 36, done. Delta compression using up to 2 threads. Compressing objects: 100% (21/21), done. Writing objects: 100% (21/21), 2.23 KiB, done. Total 21 (delta 15), reused 0 (delta 0) -----> Heroku receiving push -----> Rails app detected -----> Detected Rails is not set to serve static_assets Installing rails3_serve_static_assets... done -----> Gemfile detected, running Bundler version 1.0.3 All dependencies are satisfied -----> Installing quick_sendgrid plugin from git://github.com/pedro/quick_sendgrid.git... done. Compiled slug size is 21.6MB -----> Launching... done app deployed to Heroku To [email protected]:s4dror.git 5ea4219..6a5665b master -> master
Helaas was het niet meteen koek en ei. Zo maakt onze applicatie gebruik van SQlite3 om gegevens op te slaan. Dat is niet beschikbaar op Heroku, gelukkig is er wel een PostgreSQL database van 5MB gratis beschikbaar. Dat is groot genoeg voor onze applicatie.
Daarnaast hadden we ook problemen met file-uploads. Het bestandssysteem is namelijk gemount als read-only. Alleen lezen dus, en niet schrijven. File uploads zijn daardoor onmogelijk, tenzij je ze ergens anders host. Heroku raadt zelf aan om S3 te gebruiken. Daar kun je voor $0.15/gb/mnd je data hosten. Daar heb ik dan ook een account aangemaakt, en heb deze in Paperclip (onze file upload plugin) ingesteld als backend:
if Rails.env.production? has_attached_file :image, :styles => { :medium => "380x600>", :thumb => "240x240>", :square => "140x140#" }, :storage => :s3, :s3_credentials => "#{RAILS_ROOT}/config/s3.yml", :path => ":attachment/:id/:style.:extension", :bucket => 's4dror-heroku' else has_attached_file :image, :styles => { :medium => "380x600>", :thumb => "240x240>", :square => "140x140#" } end
Het laatste 'probleem' was dat Heroku geen mails voor jou verstuurd. Daar zul je dus een externe partij voor moeten vinden. Gelukkig is er een Heroku addon (soort plugin) beschikbaar die Sendgrid koppelt aan jouw applicatie. Het instellen is makkelijk, je moet alleen dit toevoegen aan je environment (environments/production.rb in ons geval):
ActionMailer::Base.smtp_settings = { :address => "smtp.sendgrid.net", :port => '25', :authentication => :plain, :user_name => ENV['SENDGRID_USERNAME'], :password => ENV['SENDGRID_PASSWORD'], :domain => ENV['SENDGRID_DOMAIN'] }
Daarna werkte alles als een dolle. Migrations kun je gewoon uitvoeren vanaf je eigen machine met heroku rake db:migrate. Erg gemakkelijk dus, en het mooie is, op de S3 storage na (die overigens niet veel kost met dat kleine beetje data van ons), alles gratis is!
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Long time no see, zo leek het even. Heb ondertussen echter niet stilgezeten, getuige de lijst commits op github. In de afgelopen weken zijn we erg druk geweest met onze Rails webshop, en dat valt nog niet mee.
Zoals in onze tussenpresentatie al te merken was, zijn we niet echt blij met Ruby's syntax. De taal is erg flexibel, en kan erg veel. Doet ook erg veel. Maar niet zichtbaar. Rails is wat mij betreft zwarte magie. Er gebeurd heel veel zonder dat je één regel code schrijft. Maar als datgeen niet is wat jij wil, moet je ineens allerlei code gaan schrijven. Nee, doe mij Django maar. Lekker expliciet.
We moeten echter niet zeuren, maar gewoon werk verzetten. Dus you better get over it.
Vorige week zijn we echt gestart met onze applicatie. We werken van de voor- naar de achterkant. Zoals de makers van Rails (37signals) het ooit hebben bedoelt. Roy heeft de ontwerpen gemaakt, later hebben Roy en ik ze samen omgezet naar HTML. Vanuit daar zijn we verder gaan werken, stap voor stap.
Zo heb ik me eerst gefocussed op het belangrijkste, het Product model. En dan in het specifiek het kunnen uploaden van plaatjes. Met de gem paperclip was dit een piece of cake:
class Product < ActiveRecord::Base has_attached_file :image, :styles => { :medium => "380x600>", :thumb => "240x240>", :square => "140x140#" } end
Helaas werken uploads in het PNG formaat niet, het lijkt erop dat dat heeft te maken met mijn ImageMagick installatie, ik heb namelijk geen PNG support geïnstalleerd.
Daarna ben ik me gaan bezighouden met het winkelwagentje. De code lijkt op het eerste gezicht vrij complex, maar in the end valt het allemaal best mee:
Tumblr media
Een Cart has_many LineItem, een LineItem belongs_to Cart,Product,Order. Order has_many LineItem. Omdat LineItem een gedeeld onderdeel is tussen een Order en een Cart, is de overstap van een Cart naar een Order erg simpel.
Onze Carts leven in de database. Op het moment dat een bezoeker de website bezoekt, wordt er automatisch een karretje voor hem aangemaakt als hij deze nog niet heeft:
class ApplicationController < ActionController::Base protect_from_forgery private def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart end end
Nadat het hele winkelmandje erin zat, is Roy verder gegaan met het omzetten naar een daadwerkelijke Order. Ik heb mij ondertussen vermaakt met het maken van allerhande filters. Dit doen we met has_scope gem. Hierdoor kunnen we makkelijk filters chainen. We hebben bijv. filters op kleur, jaar, type etc:
class ProductsController < ApplicationController has_scope :by_colour, :by_type, :by_year, :corked, :by_name has_scope :by_alcohol, :using => [:min, :max] has_scope :by_price, :using => [:min, :max] # GET /products # GET /products.xml def index @products = apply_scopes(Product).paginate(:page => params[:page]) end end class Product < ActiveRecord::Base scope :by_name, proc {|name|{ :conditions => ['name like ?', "%#{name}%"] }} scope :by_colour, proc {|colour|{ :conditions => { :colour => colour }}} scope :by_type, proc {|type|{ :conditions => { :type_id => type }}} scope :by_year, proc {|year|{ :conditions => { :year => year.to_i }}} scope :by_alcohol, proc {|min,max|{ :conditions => { :alcohol => min.to_i..max.to_i }}} scope :by_price, proc {|min,max|{ :conditions => { :price => min.to_f..max.to_f }}} scope :corked, lambda {|corked| where(:cork => corked == 'true') } end
In onze views roepen we de filters als volgt aan:
<%= link_to "All", params.merge(:corked => '') %> <%= link_to "Cork", params.merge(:corked => 'true') %>
Het laatste deel van de dag gister, en vandaag ben ik aan de slag gegaan met het hele RelatedProduct verhaal. Dat heb ik vandaag nog eens over mogen doen, omdat het niet goed werkte. RelatedProduct is een vreemde eend in de bijt: het is namelijk een relatie vanaf het Product model naar zichzelf:
class Product < ActiveRecord::Base has_many :related_products, :foreign_key => 'related_id' has_many :product, :through => :related_products end class RelatedProduct < ActiveRecord::Base belongs_to :product end
Gelukkig werkt ondertussen alles naar behoren. We kunnen vanuit de admin (overigens gebouwd op basis van Typus) producten koppelen aan elkaar.
Ik heb al wel de behulpzaamheid van Rails'ers mogen ervaren. Op een prettige manier. Ik had contact gezocht met de developer van de has_scope plugin om te vragen hoe we het beste filters chainable konden maken (bijv. zowel filteren op jaar als op kleur). Binnen een half uur had ik een antwoord, helemaal top!
In de komende dagen gaan we onze webshop verder perfectioneren, zodat we een mooi eindproduct hebben. Het werkt in ieder geval al verrassend goed.
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Vandaag zijn we met iedereen van de groep samengekomen. Erg lang productief werken zat er niet in, omdat het internet weer eens zo traag was als dikke stront door een trechter. Dus, voor zolang de pret duurde, hebben we met z'n allen individueel gewerkt aan de Rails for Zombies opdrachten. Leuke insteek, maar de opdrachten waren wel erg simpel.
Simpele opdrachten dus, vooral omdat de opgaven vaak letterlijk vroegen naar dingen uit de introductievideo. Wel erg leuk was de online editor, waardoor je niet constant hoefde te switchen tussen Safari en Textmate om dingen uit te proberen. Dat kon direct in je browser. Daardoor werden antwoorden ook meteen gecontroleerd. Wel zo lekker!
Binnen een goed uurtje was ik door alle opdrachten heen, helaas. Daarna was het internet ook niet veel soeps meer, en zijn we ermee gestopt. We hebben nog wel een #s4d_ror powersong gekozen: Zombie Nation - Kernkraft 400.
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Vandaag hebben Daan en ik samen gewerkt, omdat we dat prettig vinden. Zo kunnen we elkaar snel helpen bij het beantwoorden van vragen. Ik heb me gefocussed op het vertalen van de website van Slagerij de Vries naar Ruby on Rails.
Tumblr media
Al vrij snel had ik de basics van de applicatie weer draaiend dankzij de wondere wereld van de generators. Je stampt zo enkele models en controllers uit de grond.
In de applicatie heb ik twee models gemaakt, een Contact model (zodat ik het contactformulier qua input ook kan valideren)en een Product model (voor producten en aanbiedingen). Beide models zijn niet zo spannend, behalve dat het Product model een beforefilter heeft om de prijzen (die in centen zijn aangegeven) om te zetten naar een 'normaal' bedrag:
class Product < ActiveRecord::Base after_find :convert_floats private def convert_floats self.price_per_kg = self.price_per_kg.to_f/100 if self.discount != nil self.discount = self.discount_before_type_cast.to_f/100 end end end
Daarnaast heb ik enkele controllers gemaakt: een pages-, een contact- en een productscontroller. De eerste controller handelt alle 'statische' pagina's af:
class PagesController < ApplicationController def display render 'pages/content/' + params[:page] + '.html.erb' end end
Veel simpeler had het niet gekund. Om de pagina's 'mooie' URLs te geven (/home ipv. /pages/display?page=home) heb ik wat aanpassingen moeten doen in de routes:
Slagerijdevries::Application.routes.draw do root :to => "pages#display", :defaults => { :page => 'home' } match 'products' => 'products#index' match 'deals' => 'products#deals' match 'contact' => 'contact#submit_contact' match ':page' => 'pages#display' end
De 'root' regel zorgt ervoor dat de hoofdpagina (/) de homepagina laat zien in plaats van iets anders. Hier moest ik wel een public/index.html bestand voor verwijderen, het duurde even voordat ik dat door had.
Daarna was het nog een kwestie van de templates goed inrichten, en de applicatie was al een eind op weg!
-b
0 notes
bjornposts4d-blog · 14 years ago
Text
Het programmeerwerk zit er voor ons nu op. Vandaag zijn we namelijk begonnen met de 'verantwoording'; de eindpresentatie.
We zijn begonnen met de uitgangspunten die Arthur ons doormailde:
Proces, product, code etc.
Schets ook je aanpak, verwachtingen, tegenvallers
Waarom welk materiaal gebruikt?
Op basis daarvan zijn we onze stappen gaan terugvolgen en hebben we voor ieder onderdeel inhoud bedacht. In het klad is onze presentatie al helemaal klaar en de eerste slides zijn al gemaakt.
In het gesprek met Arthur, aan het eind van de middag, hebben we deze plannen doorgesproken. Arthur gaf aan dat het de bedoeling is dat het niet zozeer een opsomming moet worden, maar dat hij ook geïnteresseerd is in het 'waarom'.
Waarom hebben we besloten om direct aan de slag te gaan?
Waarom hebben we bepaalde features wel uitgewerkt en waren anderen niet interessant?
Waarom zijn we gestopt met het uitwerken van bepaalde features?
Morgen gaan we verder met het maken van onze presentatie, we zullen extra de aandacht leggen op de 'waarom' stukken. 
-b
1 note · View note
bjornposts4d-blog · 14 years ago
Link
s4ddaan:
Vandaag merkten we voor het eerst dat het verzinnen van taken steeds moeilijker wordt. Onze applicatie voldoet eigenlijk al aan bijna alle eisen die we vooraf gesteld hebben en de enige taken zijn kleine verbeteringen of bugfixes.
Bjorn is begonnen met het optimaliseren van de tweetweergaven. In...
1 note · View note
bjornposts4d-blog · 14 years ago
Link
s4ddaan:
We zijn de dag begonnen met het opnieuw opschrijven van taken. Daarbij was de realisatie van het ontwerp al aardig ver maar nog niet 100% af. We zijn gister blijven steken met enkel een search field die diende als filter. Dat is natuurlijk niet genoeg is onze uiteindelijke applicatie. Dit search...
1 note · View note
bjornposts4d-blog · 14 years ago
Text
Vandaag hebben Daan en ik weer gewerkt aan de realisatie van onze applicatie. Afgelopen week hebben we hard gewerkt aan de backend van de applicatie, en met succes. Op dit moment draait het hele syncronisatie verhaal al. Omdat de backend al klaar was, konden we vanochtend aan de slag met de frontend.
Daan is begonnen met de voorkant van de applicatie in Balsamiq (online wireframe tool) gezet, zodat we beiden snel een idee hadden van wat we moeten realiseren. Dit zonder veel tijd te verliezen aan een compleet Photoshop ontwerp, wat ons veel tijd heeft bespaard. Een compleet ontwerp zou tijdens dit project niet zoveel toevoegen, omdat dat niet belangrijk is.
Tumblr media
Terwijl Daan aan de slag was met het ontwerp, heb ik me gestort op een leuk extraatje, het schrijven van enkele testcases voor onze applicatie:
class TwitterSyncerTest(TestCase): def test_feed_url(self): # generate group + user gtc = GroupTestCase() g = gtc.generate_group() user = self.generate_user('Obi-Wan Kenobi', g) # check TwitterSyncer feed url ts = services.TwitterSyncer() self.assertEqual(ts.feed_url(user), 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=obi_wan_kenobi&since_id=1&include_rts=true')
Hoewel testcases voor nu een beetje mosterd na de maaltijd zijn (de code is al stabiel), zien we wel de voordelen. Ook als we in de komende week nog wijzigingen doen in de code kunnen we het daarna snel testen of het niks sloopt.
Aan het eind van de ochtend zijn we naar Arnhem gegaan, omdat we om 12.00u een afspraak hadden met Arthur. Hij was enthousiast over onze applicatie, en had zelfs nog wat ideeën. Deze hebben we opgeschreven. Als er tijd over is, gaan we zeker die zaken nog toevoegen.
Daarnaast hebben we in overleg met Arthur besloten om de GithubSyncer class te laten voor wat hij is, aangezien hij door geen enkele groep gebruikt wordt. We kunnen beter tijd besteden aan andere zaken, zoals integratie met South (database migrations). Door onze app te integreren met South hopen we voor altijd af te zijn van de database migration issues.
Terug thuis (later in de middag, ‘even’ op en neer duurt toch lang) zijn we weer verder gegaan met de realisatie van onze applicatie. Daan heeft wat wijzigingen in de models gedaan. We hadden namelijk het probleem dat Django Post.objects.order_by(['-tumblrpost__created', '-twitterpost__created']) niet zo leuk vindt. Hij sorteert wel, maar eerst alle tweets en daaronder alle tumblrposts. Dit probleem heeft Daan opgelost door het created veld een laag naar boven te halen: Post.objects.order_by('-created'). Problem solved.
Terwijl Daan daarmee bezig was, heb ik mij bezig gehouden met het integreren van een filtersysteem. We willen aan de frontend namelijk de mogelijkheid hebben om op bepaalde velden te kunnen filteren. Ik was al eens eerder een site tegengekomen die allerlei handige django apps verzameld: djangopackages.com. Een simpele search op ‘filter’ bracht mij al bij het gewenste resultaat, een django-filter app. Met 6k aan downloads en ruim 300 watchers leek het mij betrouwbaar. Een goede ROI dus, binnen enkele minuten had ik een goede app gevonden. Het is erg handig dat er zo’n centrale plek is voor al die plugins.
De integratie ging opzich prima, behalve een probleem met easy_install op Daan’s laptop. Na wat zoeken op internet hadden we al vrij snel een goede oplossing daarvoor gevonden, binnen 10 minuten waren we weer up and running.
Nadat de integratie er voor de basis in zat, heb ik mij gefocust op het realiseren van een simpele basis op basis van het wireframe van Daan.
-b
1 note · View note
bjornposts4d-blog · 14 years ago
Link
s4ddaan:
Deze blogpost stond nog steeds als draft, vandaar wat later ;)
Omdat we donderdag 4 november zo lekker gewerkt hebben, was ons voornemen om die streep door te trekken. Dat is ons gelukt! Zoals in Bjorn’s blogpost van gister te lezen is konden we gister niet optimaal onze stukken code beheren en...
1 note · View note
bjornposts4d-blog · 14 years ago
Text
Vandaag was de eerste dag dat Daan en ik de hele dag aan onze applicatie hebben gewerkt. We zijn 's ochtends begonnen met het samenstellen van een todolijstje, waardoor we precies wisten wat er allemaal moest gebeuren. Hierdoor werden we geforceerd om na te denken over een handige volgorde om bepaalde zaken op te pakken (bijv. eerst Models schrijven voordat je met Views begint). Het maken van een todolijstje per dag is denk ik iets wat er wel in blijft, zo hebben we een goed overzicht van wat er gedaan moet worden. Komt het todolijstje niet af? Dan schuiven de resterende items gewoon een dag door.
Daan heeft allereerst een begin gemaakt met het maken van de models. Dat ging erg snel, en dankzij de django shell (manage.py shell) en de admin interface kun je de models ook erg snel testen.
Ik was ondertussen bezig met een opzet van de command line applicatie. Ook dit kan gewoon vanuit het django framework. Het voordeel hiervan is dat we direct ook via onze models verbinding kunnen leggen met de database.
Doordat we aan dezelfde tafel zaten te werken, konden we snel vragen van elkaar beantwoorden, en kon ik al referenties naar velden in models implementeren die Daan op dat moment aan het schrijven was. Zo verloren we weinig tijd.
Na de lunch zijn we verder gegaan met het afmaken van de models en de command line applicatie, en konden we goed doorwerken, op wat kleine probleempjes na. Die probleempjes konden we echter wel direct oplossen, zonder veel tijd te verliezen.
Waardoor we wel veel tijd zijn verloren is het samenvoegen van code. Omdat we op Daan's laptop Git niet aan de gang kregen, moesten we alles handmatig samenvoegen. Dit probleem hopen we morgen opgelost te hebben, Daan upgrade naar Windows 7.
Resultaat van vandaag:
Alle models hebben een eerste versie, werken en zijn getest
Admin interface is opgezet en bevat handige features (zoeken, filteren, etc)
De command line applicatie synct tumblr posts van alle users, en is modulair, dus het toevoegen van een tweede, derde, vierde, etc. service zou niet veel werk mogen zijn.
Morgen gaan we weer verder met onze applicatie. Ik denk dat de huidige manier van werken prima is, en daarom zullen we a) weer een to-do lijstje opstellen en b) weer aan dezelfde tafel werken (zonder samen achter één computer te zitten) 
1 note · View note
bjornposts4d-blog · 14 years ago
Link
s4ddaan:
In de ochtend hebben we les gehad van Robert waarin de verschillende problemen bij een project werden besproken. Daarbij kon de klas aangeven of zij zich wel of niet konden vinden in de problemen. Enkele problemen waren Weet niet waar ik moet beginnen of Wat is goed genoeg. Met name die laatste...
1 note · View note
bjornposts4d-blog · 14 years ago
Text
Arduino “Reels Of Fortune Light” aka ROFL
Omdat ik een les had gemist, ben ik op basis van de ROFL code van Arthur begonnen met opdracht 3 en 4, maar ik ben vrij snel 'ontspoord' en heb een beetje mijn eigen plan getrokken. Ik wilde graag het volgende:
Inzet bepalen door middel van button 1, vervolgens met button 2 start de teller
Met slider 1 bepaal je de lengte voordat je 't resultaat krijgt te zien
Terwijl je 'wacht', zie je random getallen op de LCD
Na een ronde komt je resultaat in de Serial Monitor terecht
Het uitdagende van de opdracht zat 'm in het feit dat je in Arduino geen events hebt, waardoor je vrij snel terecht komt in while's. Persoonlijk vind ik dat ook meteen het vervelende aan Arduino; het nodigt mij heel erg uit om er een enorme puinbak van te maken.
De code waarmee ik uiteindelijk duizenden euro's verloren ben:
#include "_init_sparkfun.h" // globale variabelen char* res1; char* res2; char* res3; char* res4; char* res5; char* res6; char* res7; char* res8; char* res9; // rollen definities met 11 posities, 0 tm 10 index // index: 0 5 10 char* rol1[] = {"1","2","*","&","@","%","|","x",".","=", ":"}; char* rol2[] = {":","2","*","@","&","|","x","%","=",".", "1"}; char* rol3[] = {"1","2","@","*","@","%","|","*",".","=", ":"}; int rol1_pos; int rol2_pos; int rol3_pos; // led 1-9 const byte ledCharSet[10] = { B00111111,B00000110,B01011011,B01001111,B01100110,B01101101,B01111101,B00000111,B01111111,B01101111 }; int saldo = 0; int inzet = 1; void draaiRollen() { if (rol1_pos == 0) { // 1 afhalen onmogelijk, want -1 is geen geldige index // uitzondering, want rol = rond. idx wordt 10 // zo ook voor rol2 en rol3 res1 = rol1[10]; } else { res1 = rol1[rol1_pos - 1]; } if (rol2_pos == 0) { res2 = rol2[10]; } else { res2 = rol2[rol2_pos - 1]; } if (rol3_pos == 0) { res3 = rol3[10]; } else { res3 = rol3[rol3_pos - 1]; } res4 = rol1[rol1_pos]; res5 = rol2[rol2_pos]; res6 = rol3[rol3_pos]; // als idx = 10 dan +1 niet mogelijk want niet beschikbaar in array (10 idx) // dus gebruik waarde van idx 0 if (rol1_pos == 10) { res7 = rol1[0]; } else { res7 = rol1[rol1_pos + 1]; } if (rol2_pos == 10) { res8 = rol2[0]; } else { res8 = rol2[rol2_pos + 1]; } if (rol3_pos == 10) { res9 = rol3[0]; } else { res9 = rol3[rol3_pos + 1]; } } void bepaalNieuwePosities() { rol1_pos = random(11); rol2_pos = random(11); rol3_pos = random(11); //rol1_pos = 9; //rol2_pos = 9; //rol3_pos = 9; } void printRollen() { Serial.print (res1); Serial.print (" "); Serial.print (res2); Serial.print (" "); Serial.print (res3); Serial.println (""); Serial.print (res4); Serial.print (" "); Serial.print (res5); Serial.print (" "); Serial.print (res6); Serial.println (""); Serial.print (res7); Serial.print (" "); Serial.print (res8); Serial.print (" "); Serial.print (res9); Serial.println (""); } boolean checkOfPrijsHorizontaal() { if(res4 == res5 && res5 == res6) { Serial.println("> PRIJS horizontaal, inzet*30"); saldo = saldo + inzet*30; return true; } else { return false; } } boolean checkOfPrijsHorizontaalBoven() { if(res1 == res2 && res2 == res3) { Serial.println("> PRIJS horizontaal boven, inzet*12"); saldo = saldo + inzet*12; return true; } else { return false; } } boolean checkOfPrijsHorizontaalBeneden() { if(res7 == res8 && res8 == res9) { Serial.println("> PRIJS horizontaal beneden, inzet*12"); saldo = saldo + inzet*12; return true; } else { return false; } } boolean checkOfPrijsKruislings() { if( (res1 == res5 && res5 == res9) || (res3 == res5 && res5 == res7) ) { Serial.println("> PRIJS kruislings, inzet*20"); saldo = saldo + inzet*20; return true; } else { return false; } } void setup() { ds_init(); // led op 1 digitalWrite(LATCH_PIN,LOW); shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,~(ledCharSet[inzet])); digitalWrite(LATCH_PIN,HIGH); } void loop() { // button 2 = startknop, tot dat moment = inzet bepalen while(digitalRead(BUTTON2_PIN) != LOW) { // verander inzet if(digitalRead(BUTTON1_PIN) == LOW) { inzet++; if(inzet > 9) { inzet = 1; } digitalWrite(LATCH_PIN,LOW); shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,~(ledCharSet[inzet])); digitalWrite(LATCH_PIN,HIGH); delay(500); } // starten int startKnop = digitalRead(BUTTON2_PIN); if(startKnop == LOW) { Serial.println(">>> START"); Serial.print("> saldo: E "); Serial.println(saldo); Serial.print("> inzet: E "); Serial.println(inzet); Serial.println("===================="); //saldo = saldo+inzet; delay(200); // doe ronde randomSeed( analogRead(0) + analogRead(1) + analogRead(2) + analogRead(3) + analogRead(4) + analogRead(5) + millis() + micros() ); // maak 3 random nummers voor de rollen bepaalNieuwePosities(); // bepalen res1 tm res9 draaiRollen(); int msTotResultaat = analogRead(SLIDER1_PIN)/16; // we hebben niet eeuwen de tijd. while(msTotResultaat >= 0) { if(msTotResultaat == 0) { // random shit weer weghalen, inzet weer tonen digitalWrite(LATCH_PIN,LOW); shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,~(ledCharSet[inzet])); digitalWrite(LATCH_PIN,HIGH); // printen res1 tm res9 printRollen(); // check prijs if(checkOfPrijsHorizontaal() || checkOfPrijsHorizontaalBoven() || checkOfPrijsHorizontaalBeneden() || checkOfPrijsKruislings()) { delay(2000); } else { saldo = saldo - inzet; delay(500); } Serial.println("===================="); Serial.print("> saldo: E "); Serial.println(saldo); Serial.println("===================="); } else { digitalWrite(LATCH_PIN,LOW); shiftOut(DATA_PIN,CLOCK_PIN,MSBFIRST,~(ledCharSet[random(0,9)])); digitalWrite(LATCH_PIN,HIGH); delay(50); } msTotResultaat--; } } } }
Test.
0 notes