<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>TulipeMoutarde.be</title>
	<link href="https://tulipemoutarde.be/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://tulipemoutarde.be"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2023-08-24T04:00:00+02:00</updated>
	<id>https://tulipemoutarde.be/atom.xml</id>
	<entry xml:lang="en">
		<title>Dependency injection in Axum handlers. A quick tour</title>
		<published>2023-08-24T04:00:00+02:00</published>
		<updated>2023-08-24T04:00:00+02:00</updated>
		<link href="https://tulipemoutarde.be/posts/2023-08-20-depencency-injection-rust-axum/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2023-08-20-depencency-injection-rust-axum/</id>
		<content type="html">&lt;p&gt;Dependency injection is an elaborate word to say that we want to introduce
flexibility in software systems. Instead of having one big ball of functions, we
slice it into components that talk to each other. Sometimes we want to be able
to swap a component for another one in certain circumstances. Testing is one of
those circumstance: we want to test components in isolation. This is
especially true when we have external dependencies (eg., talking to a remote
APIs).&lt;&#x2F;p&gt;
&lt;p&gt;Rust is no different than all the other languages when it comes this principle.
But Rust being Rust, the user gets to decide how to do it. The language provides
the building bricks and the user chooses themself the abstractions they want
based on the performance hit they are ready to trade off for convenience.&lt;&#x2F;p&gt;
&lt;p&gt;We will start with the static dispatch approach with no flexibility whatsoever
and move to more flexible approach. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;context&quot;&gt;Context&lt;&#x2F;h2&gt;
&lt;p&gt;The context of our little exploration is an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tokio-rs&#x2F;axum&#x2F;&quot;&gt;axum&lt;&#x2F;a&gt; app that uses a
database of some sort. The database access is provided to all the handlers
through the &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;axum&#x2F;latest&#x2F;axum&#x2F;#sharing-state-with-handlers&quot;&gt;State&lt;&#x2F;a&gt; mechanism provided by Axum. We also have a
templating system to generate HTML. We picked &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;handlebars&#x2F;latest&#x2F;handlebars&#x2F;&quot;&gt;handlebars&lt;&#x2F;a&gt;
but it could be anything.&lt;&#x2F;p&gt;
&lt;p&gt;We assume that the database access is just one component that is used by the
handler. We can imagine that other components are made available through the
state (e.g., an AWS service, an external payment API or a redis connection).&lt;&#x2F;p&gt;
&lt;p&gt;All the code is available &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;axum-di-example&quot;&gt;on github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;static-dispatch-against-a-struct&quot;&gt;Static Dispatch against a struct&lt;&#x2F;h2&gt;
&lt;p&gt;This is the straightforward approach. We define a struct that will hold
everything and use it in our state.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;AppState {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;: Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;: MemoryDB,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MemoryDB {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;: Arc&amp;lt;HashMap&amp;lt;Uuid, String&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;MemoryDB {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;all_items&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;(&amp;amp;Uuid, &amp;amp;String)&amp;gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_item&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;item_id&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Uuid) -&amp;gt; Option&amp;lt;&amp;amp;String&amp;gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;build_router&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Router {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; state = AppState {
&lt;&#x2F;span&gt;&lt;span&gt;        templates: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build_templates&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;        db: MemoryDB::new(),
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Router::new()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::index))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;item&#x2F;:id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::show))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;with_state&lt;&#x2F;span&gt;&lt;span&gt;(state)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;handlers {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;(State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;gt;) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; 
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;show&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;): Path&amp;lt;Uuid&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    } 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;AppState&lt;&#x2F;code&gt; always holds a &lt;code&gt;MemoryDB&lt;&#x2F;code&gt; and our handlers are tied to it because
we&#x27;ve declared that the state holds an &lt;code&gt;AppState&lt;&#x2F;code&gt; (&lt;code&gt;State&amp;lt;AppState&amp;gt;&lt;&#x2F;code&gt; in the
handler signatures). This is the simplest way to use a shared state on all the
handlers but it is the less flexible as the DB implementation is hardcoded.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;static-dispatch-with-generics&quot;&gt;Static Dispatch with Generics&lt;&#x2F;h2&gt;
&lt;p&gt;To be able to swap the database component with another it can&#x27;t be a struct
anymore but a trait. &lt;em&gt;Coding to interfaces, not implementation&lt;&#x2F;em&gt; would say
the purist:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;async_trait&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub trait &lt;&#x2F;span&gt;&lt;span&gt;DB: Send + Sync {
&lt;&#x2F;span&gt;&lt;span&gt;    async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;all_items&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;(&amp;amp;Uuid, &amp;amp;String)&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_item&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;item_id&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Uuid) -&amp;gt; Option&amp;lt;&amp;amp;String&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;MemoryDB {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;: Arc&amp;lt;HashMap&amp;lt;Uuid, String&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;MemoryDB {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;async_trait&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;DB &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;MemoryDB {
&lt;&#x2F;span&gt;&lt;span&gt;    async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;all_items&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;(&amp;amp;Uuid, &amp;amp;String)&amp;gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_item&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;item_id&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Uuid) -&amp;gt; Option&amp;lt;&amp;amp;String&amp;gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add a generic with a trait bound to &lt;code&gt;AppState&lt;&#x2F;code&gt; and we&#x27;re done.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;AppState&amp;lt;D: DB&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;: Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;: D,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that&#x27;s where the painful part starts. Generics are viral and propagates
throughout the code if you don&#x27;t contain them.&lt;&#x2F;p&gt;
&lt;p&gt;Our handlers are not so simple anymore as we have to define the trait bounds for
each of them:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;D: DB&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;lt;D&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; 
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;show&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;D: DB&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;): Path&amp;lt;Uuid&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;lt;D&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; 
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example it is quite simple as the only generic parameter is the
database. But the more components we need to swap, the more generics (and their
bounds) we have to add &lt;em&gt;for each and every handler&lt;&#x2F;em&gt;. This situation is
well described in &lt;a href=&quot;https:&#x2F;&#x2F;jmmv.dev&#x2F;2023&#x2F;08&#x2F;rust-static-dispatch-failed-experiment.html&quot;&gt;Julio Merino&#x27;s article&lt;&#x2F;a&gt; about static
dispatch.&lt;&#x2F;p&gt;
&lt;p&gt;Traits to the rescue!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;static-dispatch-against-a-trait&quot;&gt;Static Dispatch against a trait&lt;&#x2F;h2&gt;
&lt;p&gt;Once again, traits can help. Instead of having &lt;code&gt;AppState&lt;&#x2F;code&gt; as a concrete
implementation, we can turn it into a trait which will stop the infamous
generics invasion:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub trait &lt;&#x2F;span&gt;&lt;span&gt;AppState: Clone + Send + Sync + &amp;#39;static {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;D: database::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;DB&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self::&lt;&#x2F;span&gt;&lt;span&gt;D;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &amp;amp;Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;RegularAppState {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;: Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;: MemoryDB,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;AppState &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;RegularAppState {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;D = MemoryDB;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;Self::&lt;&#x2F;span&gt;&lt;span&gt;D {
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.db
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &amp;amp;Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.templates
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The users of the &lt;code&gt;AppState&lt;&#x2F;code&gt; trait don&#x27;t have to know the actual type of &lt;code&gt;D&lt;&#x2F;code&gt;,
only types implementing the trait have to provide the actual type. For example,
the &lt;code&gt;RegularState&lt;&#x2F;code&gt; implementation og &lt;code&gt;AppState&lt;&#x2F;code&gt; says that it uses &lt;code&gt;MemoryDB&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can now build a router without knowing the explicit type of the state:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;build_router&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Router {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; state = RegularAppState {
&lt;&#x2F;span&gt;&lt;span&gt;        templates: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build_templates&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;        db: MemoryDB::new(),
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;(state)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;A: AppState&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;state&lt;&#x2F;span&gt;&lt;span&gt;: A) -&amp;gt; Router {
&lt;&#x2F;span&gt;&lt;span&gt;    Router::new()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::index::&amp;lt;A&amp;gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;item&#x2F;:id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::show::&amp;lt;A&amp;gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;with_state&lt;&#x2F;span&gt;&lt;span&gt;(state)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and the handlers are back to a sane definition:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;S: AppState&amp;gt;(State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;state&lt;&#x2F;span&gt;&lt;span&gt;): State&amp;lt;S&amp;gt;) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; 
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;show&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;S: AppState&amp;gt;(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;): Path&amp;lt;Uuid&amp;gt;, State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;state&lt;&#x2F;span&gt;&lt;span&gt;): State&amp;lt;S&amp;gt;) -&amp;gt; Html&amp;lt;String&amp;gt; { 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F; 
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A bit of trait dance and no dynamic dispatch. It is quite handy when performance
is important.&lt;&#x2F;p&gt;
&lt;p&gt;There are two drawbacks to this approach though:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;For every combination of dependencies, we have to define a new struct that
implements the &lt;code&gt;AppState&lt;&#x2F;code&gt; trait. Again, we only have the DB here but it might
become crowded quite quickly in a real application with different test
scenarios.&lt;&#x2F;li&gt;
&lt;li&gt;As &lt;code&gt;AppState&lt;&#x2F;code&gt; is a trait, there is no way to directly match agains the actual
fields in the handler definition. Components are exposed through methods on
the trait. Some might argue that it is a good thing.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;dynamic-dispatch-against-a-trait-object&quot;&gt;Dynamic Dispatch against a trait object&lt;&#x2F;h2&gt;
&lt;p&gt;This approach will be familiar for anyone coming from an object oriented
language. In Rust parlance, the trick is to use a &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch17-02-trait-objects.html&quot;&gt;trait object&lt;&#x2F;a&gt;
via the &lt;code&gt;dyn&lt;&#x2F;code&gt; keyword.&lt;&#x2F;p&gt;
&lt;p&gt;This incurs a small performance hit because the application will determine
&lt;em&gt;at runtime&lt;&#x2F;em&gt; the actual implementation to use when a function is called.
But in the context of a web application it does not matter that much (until it
does) as the overhead of all the other things (eg., database query, templating)
is much bigger.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;AppState {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt;: Handlebars&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;#39;static&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;: Arc&amp;lt;dyn DB + Send + Sync&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;build_router&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Router {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; state = AppState {
&lt;&#x2F;span&gt;&lt;span&gt;        templates: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build_templates&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;        db: Arc::new(MemoryDB::new()),
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Router::new()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::index))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;item&#x2F;:id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(handlers::show))
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;with_state&lt;&#x2F;span&gt;&lt;span&gt;(state)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Handlers are back to their initial implementation:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;(State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;gt;) -&amp;gt; Html&amp;lt;String&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;show&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;): Path&amp;lt;Uuid&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        State(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AppState&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;templates&lt;&#x2F;span&gt;&lt;span&gt; }): State&amp;lt;AppState&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; Html&amp;lt;String&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* .. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The full running code is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;axum-di-example&quot;&gt;available on github&lt;&#x2F;a&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;As usual, Rust lets you choose the abstraction level that fits the need for the
task at hand. It is sometimes daunting to know which approach is the right one
for a specific use case.&lt;&#x2F;p&gt;
&lt;p&gt;When in doubt, I would go with the simplest solution that provides enough
performance. In this case the dynamic dispatch route is the most flexible while
being more than fast enough for a web application that is driven by SQL calls
and external APIs. &lt;&#x2F;p&gt;
&lt;p&gt;If you are interested in the subject, &lt;a href=&quot;https:&#x2F;&#x2F;jmmv.dev&#x2F;&quot;&gt;Julio Merino&#x27;s blog&lt;&#x2F;a&gt; is worth a
read as he explores this space. Luca Palmieri&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;www.lpalmieri.com&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt; and book &lt;a href=&quot;https:&#x2F;&#x2F;www.zero2prod.com&#x2F;index.html&quot;&gt;Zero To
Production in Rust&lt;&#x2F;a&gt; are wonderful resources to get started in web
development with rust.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to botch an interview</title>
		<published>2019-12-23T20:06:36+02:00</published>
		<updated>2019-12-23T20:06:36+02:00</updated>
		<link href="https://tulipemoutarde.be/posts/2019-12-19-rust-interview/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2019-12-19-rust-interview/</id>
		<content type="html">&lt;p&gt;I&#x27;ve just spectacularly failed a technical interview for a Rust position. The
funny thing is that &lt;em&gt;a)&lt;&#x2F;em&gt; it&#x27;s the first time I apply&#x2F;interview for a job &lt;em&gt;b)&lt;&#x2F;em&gt;
It&#x27;s the first time I talk about Rust with experienced Rust programmers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gentle-rust&quot;&gt;Gentle Rust&lt;&#x2F;h2&gt;
&lt;p&gt;Lately, I&#x27;ve used Rust as a replacement for Ruby, Python and Swift. I like the
confidence it gives me when writing code. Going back to my code a few
weeks&#x2F;months later and not being afraid to modify it makes my life easier. To a
lesser extend Typescript (and its awesome integration into VS Code) gives me
similar feeling even though the potential to shoot yourself in the foot is still
high and the whole Javascript ecosystem feels fragile and klunky. &lt;&#x2F;p&gt;
&lt;p&gt;I usually write single thread CLI tools or HTTP servers with a full featured
framework. By doing so, I never had to really care about threading and
concurrency. As long as I don&#x27;t block the thread with IO operations I expect the
code to be fast enough. Actually, speed has never been a goal. The correctness
and the ability to change&#x2F;refactor code without fear is what really convinced me
to use Rust, performance is a byproduct.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;more-involved-rust&quot;&gt;More Involved Rust&lt;&#x2F;h2&gt;
&lt;p&gt;When doing the interview, I was clear that the team was at a &lt;em&gt;much more&lt;&#x2F;em&gt;
advanced stage. A lot of questions were about topics that I remember reading and
understanding in the Rust book but never encounter in real life. Simple example:
the &lt;code&gt;Send&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Sync&lt;&#x2F;code&gt; marker traits: I read about them, they are not a advanced
concepts, they are super useful when you deal with concurrency but yet, I never
had to explicitly mark some of my structs with them. &lt;&#x2F;p&gt;
&lt;p&gt;We also briefly mentioned the &lt;code&gt;async&lt;&#x2F;code&gt; ecosystem, how it works and what do the
available schedulers offer. This has been a hot topic in the Rust community this
year. I&#x27;ve read about futures but have never been close enough to actually have
precise answers.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s where I should have prepared this interview and review the parts for
which Rust is well known for but that I haven&#x27;t used enough.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Beware that
those concepts are not specific to Rust but they can be remote when you&#x27;ve spent
too much time in higher level languages.&lt;&#x2F;p&gt;
&lt;p&gt;The team is composed of top-notch Rust developers and I understand that they are
on the other side of the fence: technically precise, with a good understanding
of the inner working of the tech they use. That&#x27;s usually what I strive for but
I&#x27;m not there (yet?) with Rust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;duality&quot;&gt;Duality&lt;&#x2F;h2&gt;
&lt;p&gt;That made me realize that Rust has two faces: usable for people coming from
higher level programming language (like me!) while exposing everything needed to
go down and master every aspect of what you&#x27;re doing.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, it has been a great experience, the people I interact with were nice
and the process was quite smooth. I didn&#x27;t expect interviews to be so much fun
(yet stressful!). &lt;&#x2F;p&gt;
&lt;p&gt;All in all, it made me more curious about the
&lt;em&gt;fearless concurrency&lt;&#x2F;em&gt; side of Rust. I can&#x27;t wait to dive more into it.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;I was so thrown off that I couln&#x27;t even answer simple questions: what is a
&lt;code&gt;mut&lt;&#x2F;code&gt; reference? (yeah, I know... 🙄) How do Kafka and RabbitMQ differ? what is
backpressure?&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Triathlon training ≈ Startup life</title>
		<published>2019-08-29T20:06:36+02:00</published>
		<updated>2019-08-29T20:06:36+02:00</updated>
		<link href="https://tulipemoutarde.be/posts/2019-08-29-triathlon-startup/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2019-08-29-triathlon-startup/</id>
		<content type="html">&lt;p&gt;I&#x27;ve completed my first triathlon last week and it struck me how similar the journey to the race was to what I&#x27;m experiencing in the creation of &lt;a href=&quot;https:&#x2F;&#x2F;bismuthlabs.io&quot;&gt;Bismuth&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thepracticaldev.s3.amazonaws.com&#x2F;i&#x2F;6768y4tvw1q54d77omdm.jpg&quot; alt=&quot;Before the start. Pic by Lindsay Eeckhaudt&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;starting-point&quot;&gt;Starting Point&lt;&#x2F;h2&gt;
&lt;p&gt;When you&#x27;re not an accomplished athlete, signing up for a triathlon is not something you do lightly. I was an avid runner in 2012-2015 but have stopped training since then. I regularly commute by bike (~9km each way) so my legs were still in shape but I&#x27;ve hardly done more than a 20km trip in my life.&lt;&#x2F;p&gt;
&lt;p&gt;When a friend asked me to join a small group of wannabe triathletes training for &lt;a href=&quot;https:&#x2F;&#x2F;www.lagileppetrophy.be&quot;&gt;La Gileppe Trophy Orbea&lt;&#x2F;a&gt; it was hard to resist. We would not train for nothing: we had a well-identified goal. This is very different than just aiming for an abstract objective (being a triathlete). &lt;&#x2F;p&gt;
&lt;p&gt;The same goes for a startup. Aiming for startup life should not be a goal in itself. You should have a more concrete plan.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;team-network&quot;&gt;Team &amp;amp; Network&lt;&#x2F;h2&gt;
&lt;p&gt;The social aspect of the endeavour should not be underestimated. We were a group of five guys training for three sports. We were scattered throughout the region (Mons-Brussels-Liège, Belgium) and had only a few trainings together. It made little sense to meet for a one-hour run&#x2F;swim when you live 2 hours away from each other. We had a couple of longer bike trainings on Sundays though. &lt;&#x2F;p&gt;
&lt;p&gt;But not training together did not mean that there was no network effect. &lt;a href=&quot;https:&#x2F;&#x2F;www.strava.com&#x2F;&quot;&gt;Strava&lt;&#x2F;a&gt; logs and a Facebook group conversation are powerful motivation tools. We could greet ourselves when completing an early morning swim session or a late bike ride. The odds that I took my bike for a spin after a long day were a lot greater than if I was alone. It&#x27;s way too easy to postpone a task when you are the only one in town.&lt;&#x2F;p&gt;
&lt;p&gt;Humor and camaraderie work well when you are in doubt and think that you&#x27;re falling behind. Sharing content and training tricks maintained the interest and made sure we learnt faster.&lt;&#x2F;p&gt;
&lt;p&gt;The same goes for a startup team. Being alone is good when you need to be focused on the work but interactions and discussions are important for ideation, motivation and mental health.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;planning&quot;&gt;Planning&lt;&#x2F;h2&gt;
&lt;p&gt;Even though we registered for a short distance (triathlon sprint), one of us showed up with an ambitious training plan. It looked a bit too much for me. I knew from the start that I would not be able to follow. &lt;&#x2F;p&gt;
&lt;p&gt;And it&#x27;s alright. Sticking to a training plan you know you cannot follow is a stupid idea. Tune it down until you&#x27;re confident you can make it.&lt;&#x2F;p&gt;
&lt;p&gt;On my side, I hadn&#x27;t swam for ages and could barely cross the pool without losing my breath. Bike was ok-ish thanks to my commute but longer distances were an unknown territory. Running was my strongest point as I had trail running experience and knew the sensation in the legs and in my brain throughout the effort.&lt;&#x2F;p&gt;
&lt;p&gt;Knowing this, I created a plan custom tailored for me. I still don&#x27;t know if it was optimal. It probably wasn&#x27;t but it got me through the race without any hiccups so I consider it a win.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;execution-and-unplanned-changes&quot;&gt;Execution and unplanned changes&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thepracticaldev.s3.amazonaws.com&#x2F;i&#x2F;g5hdm2z7wzi3euah5j0u.jpg&quot; alt=&quot;Bike: Done. Pic by Caroline Vermeulen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Having the plan is only the beginning. This is something you cannot delegate, you&#x27;re the one in charge. Here again, the peer pressure of the group is important. You are not accountable to them but you don&#x27;t want to be the lazy ass that does not do anything.&lt;&#x2F;p&gt;
&lt;p&gt;Beware though. I&#x27;ve quickly noticed that social life can make it challenging to follow the plan. &lt;em&gt;Up for a beer and pizza tonight?&lt;&#x2F;em&gt; kind of text will challenge your focus and dedication. There&#x27;s a balance between turning into a social hermit and going out every night. Keeping the pizza but swapping the beer for sparkling water is the kind of compromise I was willing to make.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2019&#x2F;07&#x2F;09&#x2F;well&#x2F;move&#x2F;leadville-katie-arnold-ultramarathon-training-parenthood.html&quot;&gt;recent interview&lt;&#x2F;a&gt; of Katie Arnold showed that with a bit of creativity, you can mix a social life with kids and strong long distance training. &lt;&#x2F;p&gt;
&lt;p&gt;At my level, the plan is just a guideline. The goal was not to finish in the top 10, so flexibility was more important than performance. In a startup though, you might aim for more. This is okay but be aware of the impacts on your life.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polyglot&quot;&gt;Polyglot&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Triathlon or how to be mediocre at three sports&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Swim, bike and run are different disciplines. Being at least decent in the three of them is the whole game. For me, it was a revelation: it is much more fun to train for three sports than focus on one.&lt;&#x2F;p&gt;
&lt;p&gt;In a startup, founders are usually doing a bit of everything. They need to juggle between sales, code, marketing, raising money and more. The result should be a balance between these tasks. Of course, the balance is different at every stage and the founder must quickly react to a new situation. &lt;&#x2F;p&gt;
&lt;p&gt;This diversity is extremely challenging but also super fun and rewarding.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;learning-staying-humble&quot;&gt;Learning &amp;amp; staying humble&lt;&#x2F;h2&gt;
&lt;p&gt;Starting a new endeavor is always full of lessons. In triathlon training, you learn to listen to your body. You experiment. You learn how you can improve efficiency by adjusting your swimming strokes. You listen to advice (&lt;em&gt;try your wetsuit in open water before race day!&lt;&#x2F;em&gt;). Some are valid in a context but not in another. Keep them in mind though, they could be useful one day.&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;re the beginner with no experience. With practice, you will build confidence and find your rythm. Be patient but don&#x27;t be passive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;knowing-when-to-slow-down&quot;&gt;Knowing when to slow down&lt;&#x2F;h2&gt;
&lt;p&gt;In the second month of training, a pain in my knee started to develop. I slowed down training and quickly identified that the pain came from running. When cross-training it can be hard to identify a single source of trouble but in my case it was easy: my running shoes had more than 1000km. Fortunately, summer sales are always good to buy new shoes and the problem went away as fast as it appeared. &lt;&#x2F;p&gt;
&lt;p&gt;Not taking the time to slow down and identify the issue could have dramatic consequences. The same goes for a startup. You should always listen to your feelings (and to metrics) and adjust properly. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;equipment-is-not-that-important&quot;&gt;Equipment is not that important&lt;&#x2F;h2&gt;
&lt;p&gt;Some would believe that you need top-notch equipment to complete a race. This is far from true and the only two technical pieces of equipment you need is a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wetsuit&quot;&gt;swimming wetsuit&lt;&#x2F;a&gt; and a bike. &lt;&#x2F;p&gt;
&lt;p&gt;The bike is by far the most expensive thing you&#x27;ll need. The best bike to start with is the one you already have. A woman finished the triathlon on a foldable &lt;a href=&quot;https:&#x2F;&#x2F;www.brompton.com&#x2F;bikes&quot;&gt;Brompton&lt;&#x2F;a&gt; and a lot of riders had mountain bikes. Find a cheap second hand bike on craigslist and start riding. &lt;&#x2F;p&gt;
&lt;p&gt;Nowadays, most startups can be launched without any specific equipment. A laptop and a phone are all you need to get started. You don&#x27;t need a $3000+ Macbook Pro or an expensive SAP license to get started. Be smart about it and gear up only when you need to. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;be-hungry-for-more&quot;&gt;Be hungry for more&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thepracticaldev.s3.amazonaws.com&#x2F;i&#x2F;5nft2b3wzbshbh82gtv1.jpg&quot; alt=&quot;Let&#x27;s start. Pic by Caroline Vermeulen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is just the beginning of my triathlon journey. The sprint distance was a nice start but in the end of the race I still had some energy left. This means that training was good enough and that my body and mind were ready. The whole race was fun and a lot of endorphin was released that day. It&#x27;s time to plan the next one. I&#x27;m tempted to go for a longer distance this time. &lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve started to work full time on &lt;a href=&quot;https:&#x2F;&#x2F;bismuthlabs.io&quot;&gt;Bismuth&lt;&#x2F;a&gt; at around the same time that I started to train for the triathlon. Focusing on both is a challenge and some will say that having two parallel activities both requiring a lot of grit is the best way to waste it. I don&#x27;t believe it is. On the contrary, I think the two are complementary. &lt;&#x2F;p&gt;
&lt;p&gt;On bad days for Bismuth going for a run is a great way to let off some steam. On the other side, an early-swim session is a great way to start the day and is a good reason to jump out of the bed.&lt;&#x2F;p&gt;
&lt;p&gt;I can&#x27;t wait to see how these two will eventually end up!&lt;&#x2F;p&gt;
&lt;p&gt;(pictures by &lt;a href=&quot;http:&#x2F;&#x2F;www.carolinevml.be&#x2F;&quot;&gt;Caroline Vermeulen&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.instagram.com&#x2F;lilibabulle&quot;&gt;Lindsay Eeckhaudt&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Our Tech Stack: Rust, Typescript, React &amp; Swift</title>
		<published>2019-07-17T20:06:36+02:00</published>
		<updated>2019-07-17T20:06:36+02:00</updated>
		<link href="https://tulipemoutarde.be/posts/2019-07-17-tech-stack-bismuth/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2019-07-17-tech-stack-bismuth/</id>
		<content type="html">&lt;h1 id=&quot;tl-dr&quot;&gt;tl;dr&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;Rust (actix-web, Diesel)&lt;&#x2F;li&gt;
&lt;li&gt;Swift (SwiftPM, swift-ast)&lt;&#x2F;li&gt;
&lt;li&gt;Typescript&lt;&#x2F;li&gt;
&lt;li&gt;React (Atlaskit, Redux)&lt;&#x2F;li&gt;
&lt;li&gt;AWS (Fargate, PostgreSQL RDS)&lt;&#x2F;li&gt;
&lt;li&gt;Terraform&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;company-culture&quot;&gt;Company Culture&lt;&#x2F;h1&gt;
&lt;p&gt;I have a confession to make: I love discussing about tech stacks. They convey values and can tell a lot about company culture and the technical history of a technology team.&lt;&#x2F;p&gt;
&lt;p&gt;Of course they don&#x27;t always tell the whole story: I know a place that emphasises on employee happiness and where COBOL is still king.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;holy&lt;&#x2F;em&gt; stack that will solve all your problems does not exist. There is no &lt;a href=&quot;http:&#x2F;&#x2F;faculty.salisbury.edu&#x2F;%7Exswang&#x2F;Research&#x2F;Papers&#x2F;SERelated&#x2F;no-silver-bullet.pdf&quot;&gt;silver bullet&lt;&#x2F;a&gt;, remember? Instead, you pick the stack that makes the more sense to you, the one you&#x27;re comfortable with, the one that fits your use case.&lt;&#x2F;p&gt;
&lt;p&gt;It might be tempting to go all-in in the latest technologies and niche languages. When I was at the beginning of my career someone wise told me that a new venture should not have more than one &lt;em&gt;new shiny thing&lt;&#x2F;em&gt; in its stack. I believe this is true and that developers are sometimes too attracted to technologies that won&#x27;t survive the next winter.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;bismuth&quot;&gt;Bismuth&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;bismuthlabs.io&quot;&gt;Bismuth&lt;&#x2F;a&gt; is a service that takes your code, passes it through the mill and shows you where its structure is not ideal. We are still in the early stage and have hundreds of ideas but the end goal is to improve the process of developing software. Not only for developers but also for &lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;bismuthlabs&#x2F;lost-in-translation-cooperation-with-technical-people-18nn&quot;&gt;other stakeholders&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We currently focus on mobile apps but the tools and philosophy can be applied to anything.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thepracticaldev.s3.amazonaws.com&#x2F;i&#x2F;v01f5hfhxrj32a99w8tz.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-tech-stack&quot;&gt;The Tech Stack&lt;&#x2F;h1&gt;
&lt;p&gt;Bismuth has four main components:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Parsers for languages we support,&lt;&#x2F;li&gt;
&lt;li&gt;REST endpoints for API,&lt;&#x2F;li&gt;
&lt;li&gt;Workers that process the influx of code,&lt;&#x2F;li&gt;
&lt;li&gt;Visualisations engine for user interaction.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;parsers&quot;&gt;Parsers&lt;&#x2F;h2&gt;
&lt;p&gt;Parsing source code can be challenging but it&#x27;s an already solved exercise. Our motto there was not to reinvent the wheel for each programming language and don&#x27;t roll our own parser. Each environment has its own set of tools that work for them. We probably won&#x27;t be smarter than them anytime soon.&lt;&#x2F;p&gt;
&lt;p&gt;For Swift, we use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yanagiba&#x2F;swift-ast&quot;&gt;swift-ast&lt;&#x2F;a&gt;, which happen to be written in Swift. There were other options like using the C++ Swift compiler frontend but our team was mostly familiar with Swift and the library provided everything we needed.&lt;&#x2F;p&gt;
&lt;p&gt;For Java and Kotlin, we will probably go with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JetBrains&#x2F;intellij-community&#x2F;tree&#x2F;master&#x2F;uast&quot;&gt;Jetbrains UAST&lt;&#x2F;a&gt; in Kotlin.&lt;&#x2F;p&gt;
&lt;p&gt;For Javascript and Typescript there are more options: &lt;a href=&quot;https:&#x2F;&#x2F;esprima.org&#x2F;&quot;&gt;Esprima&lt;&#x2F;a&gt; (JS), &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;FreeMasen&#x2F;RESSA&quot;&gt;RESSA&lt;&#x2F;a&gt; (Rust), and the Typescript compiler itself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;api-endpoints-workers&quot;&gt;API Endpoints &amp;amp; Workers&lt;&#x2F;h2&gt;
&lt;p&gt;We chose &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;Rust&lt;&#x2F;a&gt;. That might sound surprising for a web API: dynamic languages have a good reputation for this type of work but Rust encompasses values that we believe in:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Correctness&lt;&#x2F;strong&gt;: Rust has a strong tendency to make you do things the right way. Is it very rare that a Rust library reaches the 1.0 version without being really production-ready. &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stability&lt;&#x2F;strong&gt;: The Rust team is very careful not to break things between releases. That does not mean that they are not moving fast (~6 weeks between releases)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Speed&lt;&#x2F;strong&gt;: this is less important for us but Rust is quite fast, even compared with C++ or C. &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Libraries &amp;amp; build&lt;&#x2F;strong&gt;: There are tons of libraries ready to be used in the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;&quot;&gt;crates.io&lt;&#x2F;a&gt; ecosystem. The build tool &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;cargo&#x2F;&quot;&gt;cargo&lt;&#x2F;a&gt; feels familiar if you&#x27;ve used Ruby Gems, PHP Composer or Gradle dependencies.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;All those values reflect in &lt;strong&gt;the community&lt;&#x2F;strong&gt;. It is helpful, inclusive and newbies are taken care of.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;While still being relatively young, Rust ticks a lot of boxes. Software is hard and having a language that promotes good practice feels like a friend holding your hand.&lt;&#x2F;p&gt;
&lt;p&gt;It usually takes us a bit longer to write Rust code than to hack a Ruby or JS script but the feeling Rust gives when the code compiles is that it will be correct and that it will stands the test of time. Personally, this is a feeling I hadn&#x27;t had since my &lt;a href=&quot;http:&#x2F;&#x2F;ocaml.org&#x2F;&quot;&gt;OCaml&lt;&#x2F;a&gt; days. &lt;&#x2F;p&gt;
&lt;p&gt;We believe that using Rust is also a strength when hiring new developers. Rust developers are usually sensitive to clean code: their brain has been washed by explicit error handling and a very strict compiler.&lt;&#x2F;p&gt;
&lt;p&gt;They might be much harder to find than Java developers but this can be seen as a strength as the odds to attract good developers is probably higher with Rust than Java (flame war fuel here).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ui-and-visualisation&quot;&gt;UI and Visualisation&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.typescriptlang.org&#x2F;&quot;&gt;Typescript&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;&quot;&gt;React&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;redux.js.org&#x2F;&quot;&gt;Redux&lt;&#x2F;a&gt; is now one of the standard stacks in frontend those days. Unless 4-5 years ago when the JS frontend war was fierce with a new competitor every week, we believe the winners have emerged and that we won&#x27;t see too much disruption in the few coming years (i.e., React, Angular and Vue.js have won).&lt;&#x2F;p&gt;
&lt;p&gt;Our visualisations are built with &lt;a href=&quot;https:&#x2F;&#x2F;d3js.org&#x2F;&quot;&gt;D3&lt;&#x2F;a&gt;, the de-facto standard for displaying visual data on the web and our GUI is built with &lt;a href=&quot;https:&#x2F;&#x2F;atlaskit.atlassian.com&#x2F;&quot;&gt;Atlaskit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We use this frontend stack both on the web and on our &lt;a href=&quot;https:&#x2F;&#x2F;electronjs.org&#x2F;&quot;&gt;electron&lt;&#x2F;a&gt; app. Electron can be really frustrating to work with at times but it is becoming ubiquitous on the desktop front (if God exists, she will destroy humanity when she sees how we waste our RAM). &lt;&#x2F;p&gt;
&lt;h2 id=&quot;infrastructure&quot;&gt;Infrastructure&lt;&#x2F;h2&gt;
&lt;p&gt;All this code sits into one monorepo. This is useful to keep track of everything in one place. On the negative side, it makes CI a bit harder as you have to detect which part of the app was affected. This might be alleviated by using &lt;a href=&quot;https:&#x2F;&#x2F;bazel.build&#x2F;&quot;&gt;Bazel&lt;&#x2F;a&gt; to build every components of our systems but we are not there yet.&lt;&#x2F;p&gt;
&lt;p&gt;We deploy on AWS using &lt;a href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;Terraform&lt;&#x2F;a&gt;. We had no experience either with AWS or Terraform but the documentation is good enough and it is quite easy to find support. Who doesn&#x27;t have someone who knows AWS in their circle these days?&lt;&#x2F;p&gt;
&lt;p&gt;We use &lt;a href=&quot;https:&#x2F;&#x2F;www.rabbitmq.com&#x2F;&quot;&gt;RabbitMQ&lt;&#x2F;a&gt; for messaging between all our components. We&#x27;re &lt;em&gt;very&lt;&#x2F;em&gt; far from reaching its limit and it serves us well so far.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future&quot;&gt;Future&lt;&#x2F;h2&gt;
&lt;p&gt;We don&#x27;t know yet how the future will look like but we believe our stack is solid enough to withstand it. Time will tell ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Build mobile apps with Bazel. Part 2: iOS</title>
		<published>2018-07-20T10:39:54-04:00</published>
		<updated>2018-07-20T10:39:54-04:00</updated>
		<link href="https://tulipemoutarde.be/posts/bazel-for-mobile-apps-part-2/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/bazel-for-mobile-apps-part-2/</id>
		<content type="html">&lt;p&gt;After building an Android app and its dependencies with
&lt;a href=&quot;https:&#x2F;&#x2F;bazel.build&#x2F;&quot;&gt;Bazel&lt;&#x2F;a&gt; in the &lt;a href=&quot;&#x2F;posts&#x2F;bazel-for-mobile-apps-part-1&#x2F;&quot;&gt;first post of the
series&lt;&#x2F;a&gt;, we continue our journey by adding
an iOS app to our monorepo. Read the &lt;a href=&quot;&#x2F;posts&#x2F;bazel-for-mobile-apps-part-1&#x2F;&quot;&gt;first
post&lt;&#x2F;a&gt; if you want to have more context
about what we are trying to achieve and why we use a monorepo and Bazel to build
mobile apps.&lt;&#x2F;p&gt;
&lt;p&gt;In this second post, we will see how we can express internal and external
dependencies, how to organise the monorepo directories and how to run the app
with XCode.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;directory-structure&quot;&gt;Directory structure&lt;&#x2F;h2&gt;
&lt;p&gt;We will mirror the code organization we had for the android app:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AppA-iOS&lt;&#x2F;li&gt;
&lt;li&gt;Lib-iOS&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Those two directories sit right next to their android counterpart.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;current-situation-overview&quot;&gt;Current situation overview&lt;&#x2F;h2&gt;
&lt;p&gt;Bazel has &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;bazel-and-apple.html&quot;&gt;built-in support for Apple
platforms&lt;&#x2F;a&gt;.
Almost all iOS developers use XCode to build their apps. The tricky part is that
XCode is not extensible and very rigid in the way it manages a project. All the
configuration is stored in an &lt;code&gt;xcodeproj&lt;&#x2F;code&gt; file. Multiple projects can be
combined in an &lt;code&gt;xcworkspace&lt;&#x2F;code&gt;. The chance of Apple supporting Bazel is close to
zero and that won&#x27;t change any time soon. That is why
&lt;a href=&quot;https:&#x2F;&#x2F;tulsi.bazel.build&#x2F;&quot;&gt;Tulsi&lt;&#x2F;a&gt; is born. It will generate &lt;code&gt;xcodeproj&lt;&#x2F;code&gt; files
based on the Bazel description of a build.&lt;&#x2F;p&gt;
&lt;p&gt;A popular tool in the iOS world is &lt;a href=&quot;https:&#x2F;&#x2F;cocoapods.org&#x2F;&quot;&gt;CocoaPods&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It
has over 48 thousand libraries and is used in over 3 million apps. CocoaPods
can help you scale your projects elegantly.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Almost all the libraries targeting iOS are available as a Pod. Converting a
&lt;a href=&quot;https:&#x2F;&#x2F;guides.cocoapods.org&#x2F;syntax&#x2F;podfile.html&quot;&gt;&lt;code&gt;Podfile&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to a &lt;code&gt;BUILD&lt;&#x2F;code&gt; file
feels a bit clunky but is usually trivial if the dependency list is short. &lt;&#x2F;p&gt;
&lt;p&gt;If the pod is written in Objective-C, it is possible to directly declare the pod
dependency with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pinterest&#x2F;PodToBUILD&quot;&gt;PodToBUILD&lt;&#x2F;a&gt; without
any manual process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;appa-ios&quot;&gt;AppA-iOS&lt;&#x2F;h2&gt;
&lt;p&gt;The official documentation has &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;tutorial&#x2F;ios-app.html&quot;&gt;a
tutorial&lt;&#x2F;a&gt; to
create an iOS project. It is maybe a bit outdated so it might be better to
directly read the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_apple&quot;&gt;git repo of the apple
rules&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We first import the Bazel rules in our &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git_repository&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;build_bazel_rules_apple&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;remote &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_apple.git&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tag &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.6.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@build_bazel_rules_apple&#x2F;&#x2F;apple:repositories.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;apple_rules_dependencies&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;apple_rules_dependencies&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nothing really fancy here, we add the Apple rules repo and load them. We are now
ready to create the app:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mkdir AppA-iOS
&lt;&#x2F;span&gt;&lt;span&gt;$ touch AppA-iOS&#x2F;BUILD
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;BUILD&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@build_bazel_rules_apple&#x2F;&#x2F;apple:ios.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ios_application&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Sources&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;srcs &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;glob&lt;&#x2F;span&gt;&lt;span&gt;([&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;src&#x2F;**&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;resources &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Resources&#x2F;Main.storyboard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ios_application&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;AppA-iOS&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bundle_id &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;be.tulipemoutarde.appa&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;families &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;iphone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;infoplists &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:Info.plist&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;visibility &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&#x2F;visibility:public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;deps &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:Sources&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An interesting pattern here is that the &lt;code&gt;ios_application&lt;&#x2F;code&gt; rules does not
reference the source code. Instead, all our code is bundled into a swift library
on which the app depends.&lt;&#x2F;p&gt;
&lt;p&gt;We create a &lt;code&gt;plist.info&lt;&#x2F;code&gt;, &lt;code&gt;AppDelegate.swift&lt;&#x2F;code&gt; and &lt;code&gt;Main.storyboard&lt;&#x2F;code&gt;. They don&#x27;t
do much but we want to have a buildable app as soon as possible:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;src&#x2F;AppDelegate.swift&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;UIKit
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@UIApplicationMain
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt; AppDelegate: NSObject, UIApplicationDelegate {
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; window: UIWindow?
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span&gt;application(_ application: UIApplication, didFinishLaunchingWithOptions: [UIApplicationLaunchOptionsKey : Any]?) -&amp;gt; Bool {
&lt;&#x2F;span&gt;&lt;span&gt;        print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;App has started&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return true
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;Info.plist&lt;&#x2F;code&gt; (nothing interesting in here, don&#x27;t write this by hand,
get it from an existing project):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;xml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xml &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;encoding&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;UTF-8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;?&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;DOCTYPE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;plist &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;PUBLIC &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-&#x2F;&#x2F;Apple&#x2F;&#x2F;DTD PLIST 1.0&#x2F;&#x2F;EN&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http:&#x2F;&#x2F;www.apple.com&#x2F;DTDs&#x2F;PropertyList-1.0.dtd&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;plist &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleDevelopmentRegion&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;en&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleExecutable&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;$(EXECUTABLE_NAME)&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleIdentifier&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;$(PRODUCT_BUNDLE_IDENTIFIER)&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleInfoDictionaryVersion&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;6.0&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleName&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;$(PRODUCT_NAME)&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundlePackageType&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;APPL&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleShortVersionString&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;1.0&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;CFBundleVersion&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;1&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;LSRequiresIPhoneOS&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UIMainStoryboardFile&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Main&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UIRequiredDeviceCapabilities&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;armv7&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UISupportedInterfaceOrientations&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UIInterfaceOrientationPortrait&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UIInterfaceOrientationLandscapeLeft&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;UIInterfaceOrientationLandscapeRight&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;array&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;plist&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;Resources&#x2F;Main.storyboard&lt;&#x2F;code&gt; (nothing interesting in here, don&#x27;t write
this by hand, use XCode to generate&#x2F;edit the Storyboard):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;xml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xml &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;encoding&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;UTF-8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;?&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;document &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;3.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;toolsVersion&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;11542&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;systemVersion&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;16D32&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;targetRuntime&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;iOS.CocoaTouch&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;propertyAccessControl&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;none&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;useAutolayout&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;useTraitCollections&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;colorMatched&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;initialViewController&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;BYZ-38-t0r&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;retina4_7&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;orientation&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;portrait&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;adaptation &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;fullscreen&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;device&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;deployment &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;identifier&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;iOS&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;plugIn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;identifier&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;com.apple.InterfaceBuilder.IBCocoaTouchPlugin&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;11524&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;capability &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;documents saved in the Xcode 8 format&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;minToolsVersion&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scenes&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&amp;lt;!--View Controller--&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scene &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;sceneID&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tne-QT-ifu&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;BYZ-38-t0r&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;sceneMemberID&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;viewController&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;layoutGuides&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;viewControllerLayoutGuide &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;y3c-jy-aDJ&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;viewControllerLayoutGuide &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bottom&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wfy-db-euE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;layoutGuides&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;view &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;contentMode&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;scaleToFill&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8bC-Xf-vdC&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rect &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;frame&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;width&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;375&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;height&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;667&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;autoresizingMask &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;autoresizingMask&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;widthSizable&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;heightSizable&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subviews&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                            &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;opaque&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;userInteractionEnabled&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;contentMode&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;horizontalHuggingPriority&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;251&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;verticalHuggingPriority&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;251&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;text&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Hello from Bazel&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;textAlignment&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;natural&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;lineBreakMode&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tailTruncation&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;baselineAdjustment&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;alignBaselines&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;adjustsFontSizeToFit&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;translatesAutoresizingMaskIntoConstraints&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Z9g-BR-NKm&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rect &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;frame&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;143&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;323&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;width&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;89&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;height&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fontDescription &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;fontDescription&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;pointSize&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;nil &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;textColor&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;nil &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;highlightedColor&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                            &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subviews&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;color &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;red&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;green&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;blue&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;alpha&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;colorSpace&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;custom&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;customColorSpace&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sRGB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;constraints&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                            &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;constraint &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;firstItem&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Z9g-BR-NKm&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;firstAttribute&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;centerX&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;secondItem&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8bC-Xf-vdC&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;secondAttribute&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;centerX&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;b9H-lm-x4b&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                            &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;constraint &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;firstItem&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Z9g-BR-NKm&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;firstAttribute&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;centerY&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;secondItem&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8bC-Xf-vdC&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;secondAttribute&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;centerY&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;uTp-aY-7lJ&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;constraints&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;viewController&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;placeholder &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;placeholderIdentifier&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;IBFirstResponder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;dkx-z0-nzr&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;sceneMemberID&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;firstResponder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scene&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scenes&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;document&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To recap, this is what our directory structure looks like:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ tree -L 7 AppA-iOS&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;AppA-iOS&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;├── BUILD
&lt;&#x2F;span&gt;&lt;span&gt;├── Info.plist
&lt;&#x2F;span&gt;&lt;span&gt;├── Resources
&lt;&#x2F;span&gt;&lt;span&gt;│   └── Main.storyboard
&lt;&#x2F;span&gt;&lt;span&gt;└── src
&lt;&#x2F;span&gt;&lt;span&gt;    └── AppDelegate.swift
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can now check that all the dots are connected together:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;AppA-iOS
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all goes well, you should have the &lt;code&gt;bazel-bin&#x2F;AppA-iOS&#x2F;AppA-iOS.ipa&lt;&#x2F;code&gt; file.
This is the app bundle. You must sign it before you can send it to a device.
This is where the experience starts to become cumbersome: we will generate an
XCode project to launch the app.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-xcode-with-tulsi&quot;&gt;Using XCode with Tulsi&lt;&#x2F;h2&gt;
&lt;p&gt;Time to install &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;tulsi&quot;&gt;Tulsi&lt;&#x2F;a&gt;, a tool made by the
bazel team to generate XCode projects from Bazel definitions. There are no
pre-built binaries, you must compile it yourself. It&#x27;s pretty straightforward
and it should build cleanly without any modifications.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-welcome.png&quot; alt=&quot;Tulsi welcome screen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Tulsi will generate a &lt;code&gt;.tulsiproj&lt;&#x2F;code&gt; directory containing all your configuration.
I placed the tulsiproj file next to the &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt; file and let it in git. Add
&lt;code&gt;&#x2F;tulsigen-*&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;tulsi-*&lt;&#x2F;code&gt; to the root &lt;code&gt;.gitignore&lt;&#x2F;code&gt; (like the &lt;code&gt;&#x2F;bazel-*&lt;&#x2F;code&gt;
symlinks).&lt;&#x2F;p&gt;
&lt;p&gt;It seems that having a single tulsiproj file for all your monorepo is the way to
go. You can add all your bazel packages and config into it. I haven&#x27;t used it in
a real project so this might be wrong. Only experience will tell.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-01-packages.png&quot; alt=&quot;Tulsi Package pane&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-02-shared-options.png&quot; alt=&quot;Tulsi Shared Options&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-03-configs.png&quot; alt=&quot;Tulsi Configs&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-04-xcode-running-app.png&quot; alt=&quot;Xcode running tulsi project&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Beware that XCode might not behave like you are used to. The &lt;code&gt;BUILD&lt;&#x2F;code&gt; file is the
single source of truth for building. Do not trust what you see in XCode.
Compilation flags should be set in Bazel, not XCode. Adding a file in XCode will
&lt;em&gt;not&lt;&#x2F;em&gt; include it in your build. For example, if you add a file to the sources,
you must regenerate the xcodeproj if you want to see it in XCode.&lt;&#x2F;p&gt;
&lt;p&gt;xcodeproj are just a transient container to use Apple tools on our code. I&#x27;ve
decided not to version them (&lt;code&gt;*.xcodeproj&#x2F;&lt;&#x2F;code&gt; in &lt;code&gt;.gitignore&lt;&#x2F;code&gt;). I don&#x27;t know yet
if it is the best thing to do, again only experience will tell.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s recap our directory layout:&lt;&#x2F;p&gt;
&lt;p&gt;{{&amp;lt;highlight shell &amp;quot;hl_lines=6-7 12&amp;quot;&amp;gt;}}
[EDITED FOR CLARITY]
$ tree -L 7 .
.
├── App-A-Android
├── AppA-iOS
│   ├── AppA.xcodeproj
│   │   ├── ... Xcode proj junk
│   ├── BUILD
│   ├── Info.plist
│   ├── Resources
│   └── src
├── BazelApps.tulsiproj
│   ├── Configs
│   │   └── AppA.tulsigen
│   ├── fstephany.tulsiconf-user
│   └── project.tulsiconf
├── Lib-Android
├── README.md
├── WORKSPACE
{{&lt;&#x2F;highlight&gt;}} &lt;&#x2F;p&gt;
&lt;h2 id=&quot;internal-swift-library&quot;&gt;Internal Swift library&lt;&#x2F;h2&gt;
&lt;p&gt;Pure Swift code can run on both macOS and Linux. Bazel can handle both and will
happily build Swift code even when it is not tied to iOS&#x2F;macOS. The bazel team
is reworking to unify Swift rules under a new repo:
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_swift&quot;&gt;&lt;code&gt;rules_swift&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;code&gt;. It is a work in progress and unfortunately, we can&#x27;t use &lt;&#x2F;code&gt;rules_apple&lt;code&gt;and&lt;&#x2F;code&gt;rules_swift` in the
same dependency tree yet (as of
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_apple&#x2F;releases&#x2F;tag&#x2F;0.6.0&quot;&gt;0.6.0&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_swift&#x2F;releases&#x2F;tag&#x2F;0.2.0&quot;&gt;0.2.0&lt;&#x2F;a&gt;
respectively).&lt;&#x2F;p&gt;
&lt;p&gt;So we&#x27;ll us the &lt;code&gt;swift_library&lt;&#x2F;code&gt; of the &lt;code&gt;rules_apple&lt;&#x2F;code&gt; instead of the one in
&lt;code&gt;rules_swift&lt;&#x2F;code&gt; but that might change in a near future.&lt;&#x2F;p&gt;
&lt;p&gt;We create a &lt;code&gt;Lib-Swift&lt;&#x2F;code&gt; directory and create the &lt;code&gt;BUILD&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Lib_Swift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;srcs &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;glob&lt;&#x2F;span&gt;&lt;span&gt;([&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;src&#x2F;**&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;visibility &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&#x2F;visibility:public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;module_name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;AppLib&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And here we hit a annoyance: the name of the artifact does not match the name of
the directory. This is because swift target names are limited to &lt;code&gt;[a-zA-Z0-9_]&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;module_name&lt;&#x2F;code&gt; param is important as it will be the name of the generated
Swift module (i.e., the one you will import).&lt;&#x2F;p&gt;
&lt;p&gt;We add dummy swift code to our library:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Lib-Swift&#x2F;src&#x2F;StringProvider.swift&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span&gt; StringProvider {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; baseString: String
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public init&lt;&#x2F;span&gt;&lt;span&gt;(baseString: String) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.baseString = baseString
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public func &lt;&#x2F;span&gt;&lt;span&gt;provideString() -&amp;gt; String {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(baseString) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;was the base string&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And check that it builds:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;Lib-Swift:Lib_Swift
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Time to use this new library in our main app:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;BUILD&lt;&#x2F;code&gt;:
{{&amp;lt;highlight python &amp;quot;hl_lines=10&amp;quot;&amp;gt;}}
load(&amp;quot;@build_bazel_rules_apple&#x2F;&#x2F;apple:ios.bzl&amp;quot;, &amp;quot;ios_application&amp;quot;)
load(&amp;quot;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&amp;quot;, &amp;quot;swift_library&amp;quot;)&lt;&#x2F;p&gt;
&lt;p&gt;swift_library(
name = &amp;quot;Sources&amp;quot;,
srcs = glob([&amp;quot;src&#x2F;**&amp;quot;]),
resources = [
&amp;quot;Resources&#x2F;Main.storyboard&amp;quot;,
],
deps = [&amp;quot;&#x2F;&#x2F;Lib-Swift:Lib_Swift&amp;quot;]
)&lt;&#x2F;p&gt;
&lt;p&gt;ios_application(
name = &amp;quot;AppA-iOS&amp;quot;,
bundle_id = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
families = [&amp;quot;iphone&amp;quot;],
infoplists = [&amp;quot;:Info.plist&amp;quot;],
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
deps = [&amp;quot;:Sources&amp;quot;],
)
{{&lt;&#x2F;highlight&gt;}} &lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;src&#x2F;AppDelegate.swift&lt;&#x2F;code&gt;:
{{&amp;lt;highlight swift &amp;quot;hl_lines=2 12-13&amp;quot;&amp;gt;}}
import UIKit
import AppLib&lt;&#x2F;p&gt;
&lt;p&gt;@UIApplicationMain
class AppDelegate: NSObject, UIApplicationDelegate {&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;var window: UIWindow?
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func application(_ application: UIApplication, didFinishLaunchingWithOptions: [UIApplicationLaunchOptionsKey : Any]?) -&amp;gt; Bool {
&lt;&#x2F;span&gt;&lt;span&gt;    print(&amp;quot;App has started&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    let provider = StringProvider(baseString: &amp;quot;Hello&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    print(&amp;quot;\(provider.provideString())&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    return true
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;}
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;We can build the app again to check that everything is OK:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;AppA-iOS
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When opening the XCode project, it will build and run fine but won&#x27;t show the
source code of the &lt;code&gt;AppLib&lt;&#x2F;code&gt; module. We need to regenerate the xcodeproj file:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;First add the package to the project.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-05-add-lib.png&quot; alt=&quot;Add Package to the tulsi project&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Add it to the config and add a target&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-06-add-lib-to-config.png&quot; alt=&quot;Add Lib to the config&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Regenerate the XCode project and open it&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-07-enjoy.png&quot; alt=&quot;Xcode targets&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Xcode now knows everything about the code and we can navigate easily in the app
and lib code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;external-cocoapod-library&quot;&gt;External CocoaPod library&lt;&#x2F;h2&gt;
&lt;p&gt;Many iOS apps load external libraries for common tasks.
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Carthage&#x2F;Carthage&quot;&gt;Carthage&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;cocoapods.org&#x2F;&quot;&gt;CocoaPods&lt;&#x2F;a&gt; are the most common tools to handle those
dependencies. As an example, we will import the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ReactiveX&#x2F;RxSwift&quot;&gt;RxSwift&lt;&#x2F;a&gt; and RxCocoa libraries into our
project. &lt;&#x2F;p&gt;
&lt;h3 id=&quot;manual-pod-conversion&quot;&gt;Manual Pod conversion&lt;&#x2F;h3&gt;
&lt;p&gt;The official doc for &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;migrate-cocoapods.html&quot;&gt;converting CocoaPods depedencies to
Bazel&lt;&#x2F;a&gt; is a bit
disappointing. The process is tedious:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;manually examine the
&lt;a href=&quot;https:&#x2F;&#x2F;guides.cocoapods.org&#x2F;using&#x2F;the-podfile.html&quot;&gt;Podfile&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;guides.cocoapods.org&#x2F;syntax&#x2F;podspec.html&quot;&gt;Podspecs&lt;&#x2F;a&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;download each Podspec (beware of version numbers!) and create a BUILD for each&lt;&#x2F;li&gt;
&lt;li&gt;Modify the main BUILD file to express the dependency.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Don&#x27;t worry if you find these instructions confusing, we&#x27;ll see how this
translates to RxSwift&#x2F;RxCocoa.&lt;&#x2F;p&gt;
&lt;p&gt;If you don&#x27;t want to deal with a manual process and work with Objective-C pods,
skip to the PodToBUILD section.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;rxswift&quot;&gt;RxSwift&lt;&#x2F;h4&gt;
&lt;p&gt;We see in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ReactiveX&#x2F;RxSwift&#x2F;blob&#x2F;master&#x2F;RxSwift.podspec&quot;&gt;RxSwift
Podspec&lt;&#x2F;a&gt; that
it does not have any external depencies. This will make our task easier. &lt;&#x2F;p&gt;
&lt;p&gt;We will start by adding the RxSwift code as an http archive in our &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;new_http_archive&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Rx&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ReactiveX&#x2F;RxSwift&#x2F;archive&#x2F;4.2.0.tar.gz&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;strip_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RxSwift-4.2.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sha256 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;d8474e9733075e7164732b25284c263d0b16e9c9a18393de932bd8ddded73360&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build_file &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Pods&#x2F;RxSwift&#x2F;BUILD&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The archive path was retrieved from the release page of RxSwift on Github. The
SHA signature is not mandatory but it&#x27;s a first verification step to ensure that
you are grabbing the right archive. To be sure to have reproducible builds, you
might want to store the archive file on a location you control.&lt;&#x2F;p&gt;
&lt;p&gt;An obvious downside of hardcoding the version is that we lose the ability to
update the external dependencies automatically with the build tool. Some will
see this vendoring (i.e., the act of copying an external dependency into
the source tree. Completely bypassing the original location of this dependency)
as an advantage, some as an evil thing. Choose your side but be pragmatic about
it.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;strip_prefix&lt;&#x2F;code&gt; argument is handy because the downloaded archive has a top
level directory &lt;code&gt;RxSwift-4.2.0&lt;&#x2F;code&gt; containing everything. As our BUILD file
contains relative paths to the archive content, &lt;code&gt;strip_prefix&lt;&#x2F;code&gt; will save us a
few key strokes.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, &lt;code&gt;build_file&lt;&#x2F;code&gt; contains the path containing the BUILD file we&#x27;ll use to
build stuff from this archive.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Pods&#x2F;RxSwift&#x2F;BUILD&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;swift_library&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RxSwift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;module_name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RxSwift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;srcs &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;glob&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Platform&#x2F;**&#x2F;*.swift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RxSwift&#x2F;**&#x2F;*.swift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;exclude&lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RxSwift&#x2F;Platform&#x2F;**&#x2F;*.swift&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    ),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;visibility &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&#x2F;visibility:public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;srcs&lt;&#x2F;code&gt; directories are a copy-paste from the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ReactiveX&#x2F;RxSwift&#x2F;blob&#x2F;master&#x2F;RxSwift.podspec&quot;&gt;&lt;code&gt;RxSwift podspec&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;`.&lt;&#x2F;p&gt;
&lt;p&gt;As the &lt;code&gt;Rx&lt;&#x2F;code&gt; entity is an external one, we must refer to it with a &lt;code&gt;@&lt;&#x2F;code&gt; (we saw
that in &lt;a href=&quot;&#x2F;posts&#x2F;bazel-for-mobile-apps-part-1&#x2F;#add-external-library&quot;&gt;the first
post&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build @Rx&#x2F;&#x2F;:RxSwift
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add this dependency to the main app:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;BUILD&lt;&#x2F;code&gt;:
{{&amp;lt;highlight python &amp;quot;hl_lines=12&amp;quot;&amp;gt;}}
load(&amp;quot;@build_bazel_rules_apple&#x2F;&#x2F;apple:ios.bzl&amp;quot;, &amp;quot;ios_application&amp;quot;)
load(&amp;quot;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&amp;quot;, &amp;quot;swift_library&amp;quot;)&lt;&#x2F;p&gt;
&lt;p&gt;swift_library(
name = &amp;quot;Sources&amp;quot;,
srcs = glob([&amp;quot;src&#x2F;**&amp;quot;]),
resources = [
&amp;quot;Resources&#x2F;Main.storyboard&amp;quot;,
],
deps = [
&amp;quot;&#x2F;&#x2F;Lib-Swift:Lib_Swift&amp;quot;,
&amp;quot;@Rx&#x2F;&#x2F;:RxSwift&amp;quot;
]
)&lt;&#x2F;p&gt;
&lt;p&gt;ios_application(
name = &amp;quot;AppA-iOS&amp;quot;,
bundle_id = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
families = [&amp;quot;iphone&amp;quot;],
infoplists = [&amp;quot;:Info.plist&amp;quot;],
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
deps = [&amp;quot;:Sources&amp;quot;],
)
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;AppA-iOS&#x2F;src&#x2F;AppDelegate.swift&lt;&#x2F;code&gt;:
{{&amp;lt;highlight python &amp;quot;hl_lines=3 8 17-23&amp;quot;&amp;gt;}}
import UIKit
import AppLib
import RxSwift&lt;&#x2F;p&gt;
&lt;p&gt;@UIApplicationMain
class AppDelegate: NSObject, UIApplicationDelegate {&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;let disposeBag = DisposeBag()
&lt;&#x2F;span&gt;&lt;span&gt;var window: UIWindow?
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func application(_ application: UIApplication, didFinishLaunchingWithOptions: [UIApplicationLaunchOptionsKey : Any]?) -&amp;gt; Bool {
&lt;&#x2F;span&gt;&lt;span&gt;    print(&amp;quot;App has started&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    let provider = StringProvider(baseString: &amp;quot;Hello&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    print(&amp;quot;\(provider.provideString())&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    Observable
&lt;&#x2F;span&gt;&lt;span&gt;        .just(1)
&lt;&#x2F;span&gt;&lt;span&gt;        .subscribe(
&lt;&#x2F;span&gt;&lt;span&gt;            onNext: { print(&amp;quot;Emitted \($0)&amp;quot;)},
&lt;&#x2F;span&gt;&lt;span&gt;            onCompleted: { print(&amp;quot;Stream has completed&amp;quot;) }
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;        .disposed(by: disposeBag)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    return true
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;}
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s about it, RxSwift is now working in the project. Unfortunately, it
does not seem possible to see its source code in XCode. When adding the
&lt;code&gt;Pods&#x2F;RxSwift&#x2F;BUILD&lt;&#x2F;code&gt; as a package in tulsi, it as a package in Tulsi, it cannot
find the associated source code. Which is quite understandable as this BUILD
file should be interpreted within the context of the &lt;code&gt;new_http_archive&lt;&#x2F;code&gt;. I
haven&#x27;t found an elegant solution yet. If you have an idea, &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;ping
me&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But the app builds fine (even in XCode).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;tulsi-08-rxswift.png&quot; alt=&quot;Running project with RxSwift&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;rxcocoa&quot;&gt;RxCocoa&lt;&#x2F;h4&gt;
&lt;p&gt;RxCocoa depends on RxSwift but is hosted in the same git repo. Its
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ReactiveX&#x2F;RxSwift&#x2F;blob&#x2F;master&#x2F;RxCocoa.podspec&quot;&gt;podspec&lt;&#x2F;a&gt; is
not really an issue and is easily mapped into &lt;code&gt;Pods&#x2F;RxSwift&#x2F;BUILD&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;{{&amp;lt;highlight python &amp;quot;hl_lines=15-26&amp;quot;&amp;gt;}}
load(&amp;quot;@build_bazel_rules_apple&#x2F;&#x2F;apple:swift.bzl&amp;quot;, &amp;quot;swift_library&amp;quot;)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;based-on-rxswift-podspec&quot;&gt;Based on RxSwift.podspec&lt;&#x2F;h1&gt;
&lt;p&gt;swift_library(
name = &amp;quot;RxSwift&amp;quot;,
module_name = &amp;quot;RxSwift&amp;quot;,
srcs = glob(
[&amp;quot;Platform&#x2F;&lt;strong&gt;&#x2F;*.swift&amp;quot;, &amp;quot;RxSwift&#x2F;&lt;&#x2F;strong&gt;&#x2F;&lt;em&gt;.swift&amp;quot;],
exclude= [&amp;quot;RxSwift&#x2F;Platform&#x2F;**&#x2F;&lt;&#x2F;em&gt;.swift&amp;quot;]
),
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;based-on-rxcocoa-podspec&quot;&gt;Based on RxCocoa.podspec&lt;&#x2F;h1&gt;
&lt;p&gt;swift_library(
name = &amp;quot;RxCocoa&amp;quot;,
module_name = &amp;quot;RxCocoa&amp;quot;,
srcs = glob(
[&amp;quot;Platform&#x2F;&lt;strong&gt;&#x2F;*.swift&amp;quot;, &amp;quot;RxCocoa&#x2F;&lt;&#x2F;strong&gt;&#x2F;&lt;em&gt;.{swift,h,m}&amp;quot;],
exclude= [&amp;quot;RxCocoa&#x2F;Platform&#x2F;**&#x2F;&lt;&#x2F;em&gt;.swift&amp;quot;]
),
deps = [&amp;quot;:RxSwift&amp;quot;],
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
)
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;Building RxCocoa is no different:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt; $ bazel build @Rx&#x2F;&#x2F;:RxCocoa
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;declare-pod-dependency-with-podtobuild&quot;&gt;Declare Pod dependency with PodToBUILD&lt;&#x2F;h3&gt;
&lt;p&gt;Manually converting a Pod is not always necessary as
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pinterest&#x2F;PodToBUILD&quot;&gt;PodToBUILD&lt;&#x2F;a&gt; will take care of it. It
is written by Pinterest and supports Objective-C Pods.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future&quot;&gt;Future&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_swift&quot;&gt;&lt;code&gt;rules_swift&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is slowly
replacing the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;rules_apple&quot;&gt;&lt;code&gt;rules_apple&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for
building Swift code. The new rules should work on Linux and will probably the
way to go in the future. In the meantime, &lt;code&gt;rules_apple&lt;&#x2F;code&gt; works pretty well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Adding an iOS app and library to the monorepo was not really hard. Dealing with
external libraries still requires some hand written config to map the CocoaPod
(or Swift Package) definitions. Fortunately, most of them are trivial. When Pods
are in Objective-C, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pinterest&#x2F;PodToBUILD&quot;&gt;PodToBUILD&lt;&#x2F;a&gt; makes
it easy to integrate them in the &lt;code&gt;BUILD&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;As before, you can check the source code &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;releases&#x2F;tag&#x2F;05-add-ios-app&quot;&gt;on
Github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So far we have two completely distinct worlds where iOS and Android live next to
each other but don&#x27;t share any code. This will be the topic of the next post
in the series.&lt;&#x2F;p&gt;
&lt;p&gt;As usual, &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;ping me on twitter&lt;&#x2F;a&gt; if you have any
feedback, suggestion or question.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Update&lt;&#x2F;em&gt;: Many thanks to &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;rmalik&quot;&gt;@rmalik&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jin_&quot;&gt;@jin_&lt;&#x2F;a&gt; for &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;rmalik&#x2F;status&#x2F;1020371559972663296&quot;&gt;reaching
out&lt;&#x2F;a&gt; to let me know about
PodToBUILD.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Build mobile apps with Bazel. Part 1</title>
		<published>2018-06-02T20:06:36+02:00</published>
		<updated>2018-06-02T20:06:36+02:00</updated>
		<link href="https://tulipemoutarde.be/posts/bazel-for-mobile-apps-part-1/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/bazel-for-mobile-apps-part-1/</id>
		<content type="html">&lt;p&gt;(&lt;em&gt;Update&lt;&#x2F;em&gt;: The second part on building the iOS app is &lt;a href=&quot;&#x2F;posts&#x2F;bazel-for-mobile-apps-part-2&#x2F;&quot;&gt;now
available&lt;&#x2F;a&gt;))&lt;&#x2F;p&gt;
&lt;p&gt;These days, I work a lot on software architecture and code reuse among projects
and among platforms. In this blog post I will explore a way to oragnize source
code to deal with the complexity of cross platform development.&lt;&#x2F;p&gt;
&lt;p&gt;We will build a small sample project on Android and iOS with
&lt;a href=&quot;https:&#x2F;&#x2F;bazel.build&#x2F;&quot;&gt;Bazel&lt;&#x2F;a&gt; and a monorepo. You can get the code related to
this blog post on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&quot;&gt;Github&lt;&#x2F;a&gt;. Browse
the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;tags&quot;&gt;tags&lt;&#x2F;a&gt; to see the
different steps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multi-platform-mobile-apps&quot;&gt;Multi-platform mobile apps&lt;&#x2F;h2&gt;
&lt;p&gt;One of the fallacies of mobile app development is the schism between Android and
iOS. To go the native route, an app need two different codebases: one in
Java&#x2F;Kotlin for Android and one in Objective-C&#x2F;Swift for iOS. Both require
different knowledge and different tools resulting in two different teams where
you could&#x2F;should have one. Bugs are also duplicated and business logic is not
canonical; there might be subtle differences in behavior between the apps.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cross-platform-frameworks&quot;&gt;Cross platform frameworks&lt;&#x2F;h3&gt;
&lt;p&gt;To solve this problem, cross-platform frameworks have appeared. They have
matured the past five years and they probably fill 80% of the common needs. Some
completely abstracts the underlying platform (e.g., React Native, Flutter) while
others still provide a first-class access to the native SDKs (e.g., Xamarin).
They usually still sit &lt;em&gt;on top&lt;&#x2F;em&gt; of the native languages of the platforms. They
provide hook to enter in the native world of Android and iOS.&lt;&#x2F;p&gt;
&lt;p&gt;They are no silver bullet though. Those frameworks have their quirks and
sometimes you have to dig in and work with the native SDK. Debugging can also be
a problem: is the bug in your code, in the cross platform framework or in the
native one? It is a good idea to still have people who understand each platform
and their associated tools.&lt;&#x2F;p&gt;
&lt;p&gt;They can also lag behind the official SDK. How fast do they integrate changes
from Apple and Google in the official distribution?&lt;&#x2F;p&gt;
&lt;p&gt;This blog post won&#x27;t use any of those framework. Expect a blog post in the
future to know how and when they can shine and how&#x2F;when they suck.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;good-old-c-to-the-rescue&quot;&gt;Good old C to the rescue&lt;&#x2F;h3&gt;
&lt;p&gt;Another trend is to use the &lt;em&gt;lingua franca&lt;&#x2F;em&gt; of the programming languages: the C
ABI. Most platforms can load and call libraries coded in C&#x2F;C++. Mobile
developers can leverage that situation and build cross-platform code that will
work everywhere. And by everywhere, iOS and Android are not the only target;
the gates are open to Windows, Linux, macOS and with the recent surge of
WebAssembly, web browsers are also in the visor.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;slack.engineering&#x2F;libslack-the-c-library-at-the-foundation-of-our-client-application-architecture-97470b5ef9b3&quot;&gt;Slack&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;oleb.net&#x2F;blog&#x2F;2014&#x2F;05&#x2F;how-dropbox-uses-cplusplus-cross-platform-development&#x2F;&quot;&gt;Dropbox&lt;&#x2F;a&gt;,
and &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=3HROqnw-nf4&quot;&gt;Microsoft&lt;&#x2F;a&gt; uses this approach
for their cross platform apps.&lt;&#x2F;p&gt;
&lt;p&gt;Tools exist to help. For example &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dropbox&#x2F;djinni&quot;&gt;Djinni&lt;&#x2F;a&gt;
(developed by Dropbox) is a tool that will generate the glue between C++ code
and Objective-C&#x2F;Java code from an IDL (&lt;em&gt;Interface Description Language&lt;&#x2F;em&gt;) file
that describes your data structures and functions. You can call one side from
the other, djinni handles the conversion.&lt;&#x2F;p&gt;
&lt;p&gt;When you think about it, C and C++ are not the only languages that can expose a
C ABI-compatible library. Rust and Chicken Scheme can do that as well and might
be well suited to your needs.&lt;&#x2F;p&gt;
&lt;p&gt;One of the biggest limitation of this approach is that you usually still need
the native language of the platform to interact with platform-specific APIs:
User Interface, Notifications, etc. You can share all the business logic code
but you still need some entry points for the platform APIs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-real-world-example&quot;&gt;A real-world example&lt;&#x2F;h2&gt;
&lt;p&gt;Imagine the (not so) hypothetical case where we have two apps that we ship on
the app store. If we release them on the two most common platforms, iOS and
Android, we end up with 4 different codebases.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;arch-01.png&quot; alt=&quot;Four different codebase&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As some of the features are similar between the two apps, we develop libraries
to host the common code (some business logic, some UI&#x2F;grapics elements):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;arch-02.png&quot; alt=&quot;Four apps with common lib per platform&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s already better. Especially if we had a third or fourth app. We can now add
a third layer that will be common to &lt;em&gt;all&lt;&#x2F;em&gt; the apps:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2018&#x2F;bazel-1&#x2F;arch-03.png&quot; alt=&quot;Four apps with common lib per platform&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The last layer could contain a lot of stuff: database access, network requests,
business logic, etc. With more effort we can even imagine that our &lt;code&gt;ViewModels&lt;&#x2F;code&gt;
would be shared between platforms. The small platform-specific layer between the
lib and the Apps could be bindings automatically generated.&lt;&#x2F;p&gt;
&lt;p&gt;For this blog post, we&#x27;ll stop at the second stage: different libs for each
platform. &lt;&#x2F;p&gt;
&lt;h3 id=&quot;multiple-git-repos&quot;&gt;Multiple git repos&lt;&#x2F;h3&gt;
&lt;p&gt;It is common among developers and dev shops to have separate repos for different
apps&#x2F;libs. In our case, that gives 6 git repos:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AppA-iOS &lt;&#x2F;li&gt;
&lt;li&gt;AppA-Android&lt;&#x2F;li&gt;
&lt;li&gt;AppB-iOS&lt;&#x2F;li&gt;
&lt;li&gt;AppB-Android&lt;&#x2F;li&gt;
&lt;li&gt;Lib-iOS&lt;&#x2F;li&gt;
&lt;li&gt;Lib-Android&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;lib-ios-and-lib-android-versioning&quot;&gt;Lib-iOS and Lib-Android versioning&lt;&#x2F;h3&gt;
&lt;p&gt;A solution for the libs is to version them and add them as a dependency to our
apps.&lt;&#x2F;p&gt;
&lt;p&gt;For iOS, &lt;a href=&quot;https:&#x2F;&#x2F;cocoapods.org&#x2F;&quot;&gt;CocoaPod&lt;&#x2F;a&gt; is probably the most common way to
generate a package. This means we need a private PodSpec repo to keep track of
the versions. That makes 7 git repos. The same goes for the Lib-Android, we
might want to have a git repo acting as a Maven repository (e.g., with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;synergian&#x2F;wagon-git&quot;&gt;GitWagon&lt;&#x2F;a&gt;). We now have &lt;strong&gt;8 git
repos&lt;&#x2F;strong&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;The iOS and Android libs don&#x27;t share any code yet, they are pure-Swift and
pure-Kotlin code implementing the same set of feature. It&#x27;s still better than
not having a common lib for AppA and AppB as we have two duplicates instead of
four.&lt;&#x2F;p&gt;
&lt;p&gt;Lib is used by both AppA and AppB. What if we make a breaking change into the
Lib? This is where &lt;a href=&quot;https:&#x2F;&#x2F;semver.org&#x2F;&quot;&gt;semantic versioning&lt;&#x2F;a&gt; is important and
you should have enough discipline not to break it. Unfortunately, it is quite
hard to enforce automatically.&lt;&#x2F;p&gt;
&lt;p&gt;When working on the libs, we probably want to test changes in the context of
AppA and AppB. We don&#x27;t want to publish a new version until we know that the
changes are correct. So we need a way to tell our build system to use the local
(i.e., on the developer disk) version of the lib or the published version for
building AppA and AppB. We can do that with &lt;em&gt;buildVariant&lt;&#x2F;em&gt; on Android and by
fiddling with the &lt;em&gt;Podfile&#x2F;target&lt;&#x2F;em&gt; on iOS but it can also be error prone.&lt;&#x2F;p&gt;
&lt;p&gt;Now if we work on a feature that requires changes in both the Lib and an App,
the branches for both projects should be created and checkouted in sync. What
happens if a developer starts to work on a feature on AppA and forget
to change branch in the Lib?&lt;&#x2F;p&gt;
&lt;p&gt;By experience, it is quite common to make a change in the Lib, update AppA,
forget about AppB and let it in a broken state. The CI (if we&#x27;re lucky to
have one) will catch the error but the harm is done: wasted energy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;build-tools&quot;&gt;Build tools&lt;&#x2F;h3&gt;
&lt;p&gt;By default, iOS apps are built with xcodebuild, Android apps with Gradle. If we
have libraries written in Rust, we&#x27;ll need Cargo and if we have C libraries
we&#x27;ll need CMake (or anything that can build C). Tying all those build tools
together can be quite challenging, especially when expressing dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, working on that many different git repositories is a mess. It requires
a lot of discipline and developer attention. If you develop a small app or does
not require a lot a reuse this model works perfectly fine. I&#x27;ve used it for many
years while developing Ruby On Rails app which tended to be self contained. But
once you reach a certain threshold on certain kind of projects, it is simply
painful.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bazel-and-the-monorepo&quot;&gt;Bazel and the monorepo&lt;&#x2F;h2&gt;
&lt;p&gt;That&#x27;s where a monorepo and Bazel come in. With those, we&#x27;ll throw our packaging
systems and use a unified build system.&lt;&#x2F;p&gt;
&lt;p&gt;Actually we might still need them, the ecosystems around
CMake&#x2F;Gradle&#x2F;Cocoapod&#x2F;xcodebuild are too pervasive to ignore. When developing an
app, it is quite common to rely on 3rd party libraries that are packaged with
the native tools of the platform. &lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ll go the full route and use a monorepo. Our previous git repositories will
be merged into one. Each previous repo will be a top level directory in the new
one. This might sound crazy (or event heretic) but stick with me here.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bazel&quot;&gt;Bazel&lt;&#x2F;h3&gt;
&lt;p&gt;Blaze is a build system initially developed internally at Google. They open
sourced it in 2015 under the name &lt;a href=&quot;https:&#x2F;&#x2F;bazel.build&#x2F;&quot;&gt;Bazel&lt;&#x2F;a&gt;. Developers that
left Google before Blaze was open source were so fond of it that they
re-developed it to build stuff at the companies they were joining. That&#x27;s how
&lt;a href=&quot;https:&#x2F;&#x2F;buckbuild.com&#x2F;&quot;&gt;Buck&lt;&#x2F;a&gt; (by Facebook) and
&lt;a href=&quot;https:&#x2F;&#x2F;www.pantsbuild.org&#x2F;&quot;&gt;Pants&lt;&#x2F;a&gt; (by Twitter) were born.&lt;&#x2F;p&gt;
&lt;p&gt;Today, Bazel is widely used and can build a lot of different languages Uber,
Dropbox, Etsy, Huawei, Stripe, SpaceX, Pinterest and many others are building
software with it (links at the bottom of the post).&lt;&#x2F;p&gt;
&lt;p&gt;Conceptually Bazel is quite simple. You have a &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt; file at the top of
your project. This is where you&#x27;ll load and configure all the rules you&#x27;ll need
to build your project. There are official rules for a lot of different stacks
(e.g., C&#x2F;C++, Java, Android, Go, Kotlin).&lt;&#x2F;p&gt;
&lt;p&gt;In every directory containing a buildable artifact you&#x27;ll have a &lt;code&gt;BUILD&lt;&#x2F;code&gt; file.
It describes where the files to compile are, the dependencies you need and other
configuration options like the visibility of the build output.&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s basically it. Bazel will build the dependency graph and aggressively
cache the artifacts that have already been built. That&#x27;s why you want to have a
lot of small modules instead of a big one containing everything. Bazel
encourages you to keep everything small and compose your code from smaller
parts.&lt;&#x2F;p&gt;
&lt;p&gt;A side effect of this layout is that someone modifying a library must ensure
that all the parts that depend on it are not broken. Bazel has a query system to
let you see the impact of modifying one unit of code. As everything is in the
same repo, the developer has everything she needs to ensure that the build is
not broken. She doesn&#x27;t need the discipline to create a branch for each repo
affected by the feature she&#x27;s working on as everything is in the same place.&lt;&#x2F;p&gt;
&lt;p&gt;When the provided rules are not enough, it is possible to code your own using
&lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;skylark&#x2F;language.html&quot;&gt;Skylark&lt;&#x2F;a&gt;, a
language derived from Python.&lt;&#x2F;p&gt;
&lt;p&gt;All of this is well in theory but in practice, how does it work?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initial-setup&quot;&gt;Initial setup&lt;&#x2F;h3&gt;
&lt;p&gt;We will create a small Android App that displays a string from a Java lib. In
future post, we will add a C library that will be called with JNI. We will then
add more complex data structure and iOS to the mix.&lt;&#x2F;p&gt;
&lt;p&gt;You can follow the whole project on this &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;&quot;&gt;Github
repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Create a single top-level directory for all our code. This directory will be
versioned in a unique Git repo. Feel free to use any other VCS. It does not
really matter at this point.&lt;&#x2F;p&gt;
&lt;p&gt;Create a &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt; file. This file will inform Bazel of all the tools we need
to build the code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-appa-android&quot;&gt;Create AppA-Android&lt;&#x2F;h3&gt;
&lt;p&gt;Add the Android SDK to the &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;WORKSPACE&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;load(&amp;quot;@bazel_tools&#x2F;&#x2F;tools&#x2F;build_defs&#x2F;repo:maven_rules.bzl&amp;quot;, &amp;quot;maven_aar&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;android_sdk_repository(
&lt;&#x2F;span&gt;&lt;span&gt;    name = &amp;quot;androidsdk&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    api_level = 27,
&lt;&#x2F;span&gt;&lt;span&gt;    build_tools_version = &amp;quot;27.0.3&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This first instruction makes the &lt;code&gt;maven_aar&lt;&#x2F;code&gt; rules available. It is useful to
handle android libraries in the &lt;code&gt;.aar&lt;&#x2F;code&gt; format. The second one tells bazel the
configuration of the Android SDK that we want to use.&lt;&#x2F;p&gt;
&lt;p&gt;Android usage is fully documented on the &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;bazel-and-android.html&quot;&gt;official
website&lt;&#x2F;a&gt;. All
the possible options are listed under the &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;be&#x2F;android.html&quot;&gt;Android
Rules&lt;&#x2F;a&gt;.Ensure that you
have your &lt;code&gt;$ANDROID_HOME&lt;&#x2F;code&gt; environment variable correctly setup so Bazel can pick
the android tools (see the &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;command-line&#x2F;variables#set&quot;&gt;android doc&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;We can now create the android app. Beware that we don&#x27;t use the typical Gradle
layout but a very barebone one:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ tree -L 7 App-A-Android&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;App-A-Android&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;├── BUILD
&lt;&#x2F;span&gt;&lt;span&gt;└── src
&lt;&#x2F;span&gt;&lt;span&gt;    └── main
&lt;&#x2F;span&gt;&lt;span&gt;        ├── AndroidManifest.xml
&lt;&#x2F;span&gt;&lt;span&gt;        ├── java
&lt;&#x2F;span&gt;&lt;span&gt;        │   └── be
&lt;&#x2F;span&gt;&lt;span&gt;        │       └── tulipemoutarde
&lt;&#x2F;span&gt;&lt;span&gt;        │           └── appa
&lt;&#x2F;span&gt;&lt;span&gt;        │               └── MainActivity.java
&lt;&#x2F;span&gt;&lt;span&gt;        └── res
&lt;&#x2F;span&gt;&lt;span&gt;            ├── drawable
&lt;&#x2F;span&gt;&lt;span&gt;            │   └── ic_launcher_background.xml
&lt;&#x2F;span&gt;&lt;span&gt;            ├── layout
&lt;&#x2F;span&gt;&lt;span&gt;            │   └── activity_main.xml
&lt;&#x2F;span&gt;&lt;span&gt;            ├── all-the-mipmap-folders
&lt;&#x2F;span&gt;&lt;span&gt;            └── values
&lt;&#x2F;span&gt;&lt;span&gt;                ├── colors.xml
&lt;&#x2F;span&gt;&lt;span&gt;                ├── strings.xml
&lt;&#x2F;span&gt;&lt;span&gt;                └── styles.xml
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You&#x27;ll notice the &lt;code&gt;BUILD&lt;&#x2F;code&gt; file right under the &lt;code&gt;App-A-Android&lt;&#x2F;code&gt; folder. It
describes how to build this particular artifact:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;App-A-Android&#x2F;BUILD&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;android_binary(
&lt;&#x2F;span&gt;&lt;span&gt;    name = &amp;quot;AppA-Android&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    custom_package = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    manifest = &amp;quot;src&#x2F;main&#x2F;AndroidManifest.xml&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    srcs = glob([&amp;quot;src&#x2F;main&#x2F;java&#x2F;**&amp;quot;]),
&lt;&#x2F;span&gt;&lt;span&gt;    resource_files = glob([&amp;quot;src&#x2F;main&#x2F;res&#x2F;**&amp;quot;]),
&lt;&#x2F;span&gt;&lt;span&gt;    visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nothing really fancy here, it should be readable. Note that the &lt;code&gt;name&lt;&#x2F;code&gt; property
(AppA-Android in our case) will be used to identify the entity when building it
or when referencing it. Once again, the &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;be&#x2F;android.html#android_binary&quot;&gt;full documentation for
&lt;code&gt;android_binary&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
is available.&lt;&#x2F;p&gt;
&lt;p&gt;We can now check if we can build the project:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;App-A-Android:AppA-Android
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you have a device plugged in or a simulator running, you can directly launch
the app on it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel mobile-install &#x2F;&#x2F;App-A-Android:AppA-Android
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;mobile-install&lt;&#x2F;code&gt; has &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;user-manual.html#mobile-install&quot;&gt;a myriad of ptions&lt;&#x2F;a&gt; that you can use to customize the launch of the app (e.g., cold start, incremental updates).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;add-external-library&quot;&gt;Add external library&lt;&#x2F;h3&gt;
&lt;p&gt;Almost all Android apps use external libraries to perform various actions.
Developers can express the dependencies in the gradle build file. Dependencies
are usually shipped as regular &lt;code&gt;jar&lt;&#x2F;code&gt; archive or as &lt;code&gt;aar&lt;&#x2F;code&gt; if they ship with
resources. Bazel supports both of them natively.&lt;&#x2F;p&gt;
&lt;p&gt;We will add &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JakeWharton&#x2F;timber&quot;&gt;Timber&lt;&#x2F;a&gt;, a small log library
to our project. We first need to add the library to our WORKSPACE. Doing so will
make it available for all the BUILD files:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;WORKSPACE&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@bazel_tools&#x2F;&#x2F;tools&#x2F;build_defs&#x2F;repo:maven_rules.bzl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;maven_aar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;maven_aar&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;timber&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;artifact&lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;com.jakewharton.timber:timber:4.7.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first instruction will load the Bazel maven rules and the second will
actually point to the external dependency. &lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;App-A-Android&#x2F;BUILD&lt;&#x2F;code&gt;:
{{&amp;lt;highlight python &amp;quot;hl_lines=8-10&amp;quot;&amp;gt;}}
android_binary(
name = &amp;quot;AppA-Android&amp;quot;,
custom_package = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
manifest = &amp;quot;src&#x2F;main&#x2F;AndroidManifest.xml&amp;quot;,
srcs = glob([&amp;quot;src&#x2F;main&#x2F;java&#x2F;&lt;strong&gt;&amp;quot;]),
resource_files = glob([&amp;quot;src&#x2F;main&#x2F;res&#x2F;&lt;&#x2F;strong&gt;&amp;quot;]),
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
deps = [
&amp;quot;@timber&#x2F;&#x2F;aar&amp;quot;,
],
)
{{&amp;lt; &#x2F; highlight &amp;gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;Notice how the &lt;code&gt;deps&lt;&#x2F;code&gt; param got a reference to Timber. In this case, the
dependency is an aar package but it could have been a java lib that is in your
monorepo. The monorepo and Bazel are well suited to code that does not depend on
a lot of external dependencies. Google probably has &lt;em&gt;a lot&lt;&#x2F;em&gt; of internal code to
perform various tasks while smaller companies probably depends more on external
libraries.&lt;&#x2F;p&gt;
&lt;p&gt;We can now import Timber in our code and check that everything builds fine:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;MainActivity.java&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...&#x2F;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;timber.log.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Timber&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import static &lt;&#x2F;span&gt;&lt;span&gt;timber.log.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Timber&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;DebugTree&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...&#x2F;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;protected&lt;&#x2F;span&gt;&lt;span&gt; void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onCreate&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Bundle&lt;&#x2F;span&gt;&lt;span&gt; savedInstanceState) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onCreate&lt;&#x2F;span&gt;&lt;span&gt;(savedInstanceState);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Timber&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;plant&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;new &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;DebugTree&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;setContentView&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;R&lt;&#x2F;span&gt;&lt;span&gt;.layout.activity_main);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that we&#x27;ve imported the external dependency in the WORKSPACE file and refer
to it in the BUILD file.&lt;&#x2F;p&gt;
&lt;p&gt;The resulting code is visible as &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;releases&#x2F;tag&#x2F;02-add-external-lib-to-android-project&quot;&gt;a tag in the sample
project&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;add-google-maven-repository&quot;&gt;Add Google Maven repository&lt;&#x2F;h3&gt;
&lt;p&gt;Since Android Studio 3.0, Google distributes android libraries through a
&lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;build&#x2F;dependencies#google-maven&quot;&gt;dedicated Maven
repo&lt;&#x2F;a&gt;.
Unfortunately it does not to work natively with Bazel. The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;gmaven_rules&quot;&gt;gmaven
rules&lt;&#x2F;a&gt; is a temporary (?) workaround
to alleviate this issue. It feels like a ugly hack but it works.&lt;&#x2F;p&gt;
&lt;p&gt;gmaven_rules manually hardcodes all the libraries provided by Google in its
maven repository in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;gmaven_rules&#x2F;blob&#x2F;master&#x2F;gmaven.bzl&quot;&gt;a single
file&lt;&#x2F;a&gt;. This
means the code has to be updated if you need the latest version of the libs.&lt;&#x2F;p&gt;
&lt;p&gt;Add the following in &lt;code&gt;WORKSPACE&lt;&#x2F;code&gt;:
{{&lt;highlight python&gt;}}
GMAVEN_TAG = &amp;quot;20180513-1&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;http_archive(
name = &amp;quot;gmaven_rules&amp;quot;,
strip_prefix = &amp;quot;gmaven_rules-%s&amp;quot; % GMAVEN_TAG,
url = &amp;quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;gmaven_rules&#x2F;archive&#x2F;%s.tar.gz&amp;quot; % GMAVEN_TAG,
)&lt;&#x2F;p&gt;
&lt;p&gt;load(&amp;quot;@gmaven_rules&#x2F;&#x2F;:gmaven.bzl&amp;quot;, &amp;quot;gmaven_rules&amp;quot;)&lt;&#x2F;p&gt;
&lt;p&gt;gmaven_rules()
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;Check the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bazelbuild&#x2F;gmaven_rules&#x2F;releases&quot;&gt;gmaven_rules releases
page&lt;&#x2F;a&gt; to find the right
&lt;code&gt;GMAVEN_TAG&lt;&#x2F;code&gt; to use when you read this. Once the WORKSPACE has the gmaven_rules,
we can use them in the BUILD file of our android app:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;App-A-Android&#x2F;BUILD&lt;&#x2F;code&gt;:
{{&amp;lt;highlight python &amp;quot;hl_lines=1 12&amp;quot;&amp;gt;}}
load(&amp;quot;@gmaven_rules&#x2F;&#x2F;:defs.bzl&amp;quot;, &amp;quot;gmaven_artifact&amp;quot;)&lt;&#x2F;p&gt;
&lt;p&gt;android_binary(
name = &amp;quot;AppA-Android&amp;quot;,
custom_package = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
manifest = &amp;quot;src&#x2F;main&#x2F;AndroidManifest.xml&amp;quot;,
srcs = glob([&amp;quot;src&#x2F;main&#x2F;java&#x2F;&lt;strong&gt;&amp;quot;]),
resource_files = glob([&amp;quot;src&#x2F;main&#x2F;res&#x2F;&lt;&#x2F;strong&gt;&amp;quot;]),
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
deps = [
&amp;quot;@timber&#x2F;&#x2F;aar&amp;quot;,
gmaven_artifact(&amp;quot;com.android.support:appcompat-v7:aar:27.1.1&amp;quot;),
],
)
{{&lt;&#x2F;highlight &gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;We can now extends &lt;code&gt;AppCompatActivity&lt;&#x2F;code&gt; instead of the &lt;code&gt;Activity&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;{{&lt;highlight java&gt;}}
package be.tulipemoutarde.appa;&lt;&#x2F;p&gt;
&lt;p&gt;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import timber.log.Timber;
import static timber.log.Timber.DebugTree;&lt;&#x2F;p&gt;
&lt;p&gt;public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Timber.plant(new DebugTree());
setContentView(R.layout.activity_main);
}
}
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;We can now build an Android app with dependencies on both Google and external
libraries. Check the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;releases&#x2F;tag&#x2F;03-add-appcompat-as-dep&quot;&gt;git tag on example
repo&lt;&#x2F;a&gt;
if needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-lib-android&quot;&gt;Create Lib-Android&lt;&#x2F;h3&gt;
&lt;p&gt;This is getting interesting. We will add a library inside our monorepo. This
library will be available for &lt;em&gt;any&lt;&#x2F;em&gt; BUILD file in the whole repo.&lt;&#x2F;p&gt;
&lt;p&gt;We create a new folder that will contain all our code: &lt;code&gt;$ROOT&#x2F;Lib-Android&lt;&#x2F;code&gt;. Once
again, we need to tell Bazel how to build the library in the BUILD file.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Lib-Android&#x2F;BUILD&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;android_library(
&lt;&#x2F;span&gt;&lt;span&gt;    name = &amp;quot;Lib-Android&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    srcs = glob([&amp;quot;src&#x2F;**&amp;quot;]),
&lt;&#x2F;span&gt;&lt;span&gt;    visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The visibility parameter tells Bazel that we want the artifact to be available
everywhere. As we want to reuse this library in the main Android app, it should
be visible.&lt;&#x2F;p&gt;
&lt;p&gt;Our Java code is pretty simple.
&lt;code&gt;Lib-Android&#x2F;src&#x2F;be&#x2F;tulipemoutarde&#x2F;lib&#x2F;StringProvider.java&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;package &lt;&#x2F;span&gt;&lt;span&gt;be.tulipemoutarde.lib;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;StringProvider &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;baseString;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;StringProvider&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;baseString&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;this&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;.baseString &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt; baseString;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;String &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getAugmentedString&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;() {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Processed &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; +&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt; baseString;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can now build the lib in isolation:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;Lib-Android
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that this time we didn&#x27;t specify the name of the artifact to build. This is
because the identifier given to the lib matches the folder name. We couldn&#x27;t do
this with the android app because the folder is named &lt;code&gt;App-A-Android&lt;&#x2F;code&gt; while the
app identifier is &lt;code&gt;AppA-Android&lt;&#x2F;code&gt; (notice the extra &lt;code&gt;-&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;We can now add the library as a dependency to the main app:&lt;&#x2F;p&gt;
&lt;p&gt;{{&amp;lt;highlight python &amp;quot;hl_lines=11&amp;quot;&amp;gt;}}
load(&amp;quot;@gmaven_rules&#x2F;&#x2F;:defs.bzl&amp;quot;, &amp;quot;gmaven_artifact&amp;quot;)&lt;&#x2F;p&gt;
&lt;p&gt;android_binary(
name = &amp;quot;AppA-Android&amp;quot;,
custom_package = &amp;quot;be.tulipemoutarde.appa&amp;quot;,
manifest = &amp;quot;src&#x2F;main&#x2F;AndroidManifest.xml&amp;quot;,
srcs = glob([&amp;quot;src&#x2F;main&#x2F;java&#x2F;&lt;strong&gt;&amp;quot;]),
resource_files = glob([&amp;quot;src&#x2F;main&#x2F;res&#x2F;&lt;&#x2F;strong&gt;&amp;quot;]),
visibility = [&amp;quot;&#x2F;&#x2F;visibility:public&amp;quot;],
deps = [
&amp;quot;&#x2F;&#x2F;Lib-Android&amp;quot;,
&amp;quot;@timber&#x2F;&#x2F;aar&amp;quot;,
gmaven_artifact(&amp;quot;com.android.support:appcompat-v7:aar:27.1.1&amp;quot;),
],
)
{{&lt;&#x2F;highlight&gt;}}&lt;&#x2F;p&gt;
&lt;p&gt;Ugh. All the deps are written differently. &lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;&#x2F;Lib-Android&lt;&#x2F;code&gt; is the simplest. &lt;code&gt;&#x2F;&#x2F;&lt;&#x2F;code&gt; represents the root of the project where
the WORKSPACE file lies. We simply reference the path and name of the
internal dependency.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;@timber&#x2F;&#x2F;aar&lt;&#x2F;code&gt; is already a bit different. The &lt;code&gt;@&lt;&#x2F;code&gt; means that we reference an
external dependency. &lt;code&gt;&#x2F;&#x2F;aar&lt;&#x2F;code&gt; tells we want the aar variant of this dependency.&lt;&#x2F;li&gt;
&lt;li&gt;Finally, &lt;code&gt;gmaven_artifact()&lt;&#x2F;code&gt; is defined when we imported the gmaven_rules. It
will convert the Gradle dependency notation to match the full bazel name given
by the gmaven_rules.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Finally we can use the code in our Activity:&lt;&#x2F;p&gt;
&lt;p&gt;{{&amp;lt;highlight java &amp;quot;hl_lines=16-17 3&amp;quot;&amp;gt;}}
package be.tulipemoutarde.appa;&lt;&#x2F;p&gt;
&lt;p&gt;import be.tulipemoutarde.lib.StringProvider;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import timber.log.Timber;
import static timber.log.Timber.DebugTree;&lt;&#x2F;p&gt;
&lt;p&gt;public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Timber.plant(new DebugTree());
setContentView(R.layout.activity_main);&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;    StringProvider provider = new StringProvider(&amp;quot;Bazel&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;    Timber.d(&amp;quot;Got an augmented string %s&amp;quot;, provider.getAugmentedString());
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;}
{{&lt;&#x2F;highlight&gt;}} &lt;&#x2F;p&gt;
&lt;p&gt;We can now re-build the app:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ bazel build &#x2F;&#x2F;App-A-Android:AppA-Android
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Bazel is smart enough to know when to recompile the lib. As usual, you&#x27;ll find
the sample project at this stage under a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;bazel-blog-post&#x2F;releases&#x2F;tag&#x2F;04-add-internal-java-lib&quot;&gt;git
tag&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h3&gt;
&lt;p&gt;Android Instrumentation Tests are still experimental in Bazel. They were
introduced in 0.12 and are maybe still a moving target. &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;android-instrumentation-test.html&quot;&gt;The
documentation&lt;&#x2F;a&gt;
has a step by step tutorial, we won&#x27;t go through it at the moment.&lt;&#x2F;p&gt;
&lt;p&gt;The only downside is that we need to create a dummy android app if we want to
test the library in isolation of the main app in an instrumentation test. This
is also true when using Gradle.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-feeling-and-conclusion&quot;&gt;General feeling and conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;It is the first time I use Bazel and my impressions are mixed. It feels really
robust and forces the developers to think in small modules that you can mix and
match together. &lt;&#x2F;p&gt;
&lt;p&gt;Bazel assumes that all your dependencies are available &lt;em&gt;in-house&lt;&#x2F;em&gt;. This is
certainly true for companies like Google but not for smaller ones. Dealing with
external dependencies feels alien. There are projects to generate rules from
native tools but they feel clunky (I&#x27;m looking at you gmaven_rules()). If your
language of choice has a standard tool for dependency management (e.g., NPM,
Bundler, CocoaPod, Cargo), you will need some duct tape to integrate it into
Bazel. It is not &lt;em&gt;that&lt;&#x2F;em&gt; bad but certainly something to check if you plan to
switch to Bazel.&lt;&#x2F;p&gt;
&lt;p&gt;The monorepo setup is quite frankly a game changer for at least one of my
current clients. Not all the projects I work on would benefit from it but it&#x27;s
a new tool that I&#x27;m happy to have in my toolbox.&lt;&#x2F;p&gt;
&lt;p&gt;I believe that a shop developing for a single platform (e.g., iOS) could benefit
from Bazel. If you have 4 or 5 apps in the App Store, they are good chances that
you have some code that you reuse among all of them. Some people uses symlinks
and&#x2F;or git submodules to deal with the situation. If it is your case, you might
want to investigate Bazel to see if it could handle your workflow.&lt;&#x2F;p&gt;
&lt;p&gt;In the following blog posts we will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Lib in C and use it from the Android App (expect other shenanigans
in the deps declaration)&lt;&#x2F;li&gt;
&lt;li&gt;Create an iOS App and Lib&lt;&#x2F;li&gt;
&lt;li&gt;IDE Support (both Android Studio and Xcode)&lt;&#x2F;li&gt;
&lt;li&gt;Pass data structures between C&#x2F;C++ and Kotlin&#x2F;Java&lt;&#x2F;li&gt;
&lt;li&gt;Use Rust instead of C&#x2F;C++&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If I find the time and the motivation, I would like to cover some other cases: &lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Build a React Native app&lt;&#x2F;li&gt;
&lt;li&gt;Build an Electron app&lt;&#x2F;li&gt;
&lt;li&gt;Build a JavaFX app&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;m exploring Bazel as I write this series so I probably missed a few things.
Please &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;ping me&lt;&#x2F;a&gt; if you have any remark or
question. &lt;&#x2F;p&gt;
&lt;p&gt;([&lt;em&gt;Update&lt;&#x2F;em&gt;] The second part on building the iOS app is &lt;a href=&quot;&#x2F;posts&#x2F;bazel-for-mobile-apps-part-2&#x2F;&quot;&gt;now
available&lt;&#x2F;a&gt;))&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;eng.uber.com&#x2F;ios-monorepo&#x2F;&quot;&gt;Uber monorepo iOS&lt;&#x2F;a&gt; (Mar 6, 2017)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;eng.uber.com&#x2F;android-monorepo&#x2F;&quot;&gt;Uber monorepo Android&lt;&#x2F;a&gt; (May 11, 2017)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;danluu.com&#x2F;monorepo&#x2F;&quot;&gt;Dan Luu monorepo blog post&lt;&#x2F;a&gt; (May 2015)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@Jakeherringbone&#x2F;you-too-can-love-the-monorepo-d95d1d6fcebe&quot;&gt;Alex Eagle, Angular Monorepo&lt;&#x2F;a&gt; (Oct 18, 2017)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wewAVF-DVhs&quot;&gt;Pinterest tips &amp;amp; trick talk&lt;&#x2F;a&gt; (Video)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=muvU1DYrY0w&quot;&gt;Bazel at Dropbox&lt;&#x2F;a&gt; (Video)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=t_3bckhV_YI&quot;&gt;Bazel at SpaceX&lt;&#x2F;a&gt; (Video)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>About</title>
		<published>2018-01-12T10:59:57+01:00</published>
		<updated>2018-01-12T10:59:57+01:00</updated>
		<link href="https://tulipemoutarde.be/about/" type="text/html"/>
		<id>https://tulipemoutarde.be/about/</id>
		<content type="html">&lt;p&gt;I&#x27;m Francois and I&#x27;m interested in how we build software. After years of
freelancing on Rails and native mobile apps, I founded and crashed a
&lt;a href=&quot;https:&#x2F;&#x2F;bismuthlabs.io&quot;&gt;startup&lt;&#x2F;a&gt; in 2019. It was a fun, stressful and exciting
experience but I&#x27;m now looking for a new opportunity. &lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m an avid learner and I don&#x27;t mind diving into a new tech stack. I&#x27;m comfortable
with Rails, Typescript, React, ObjC&#x2F;Swift, Kotlin and more recently with Rust.
Infrastucture wise I usually go with Postgres, Docker and Terraform.
That does not mean that I haven&#x27;t played with other stacks (e.g., Python, AWS,
Ansible) but we have to draw the line somewhere. &lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m interested in systems and would love to dive lower in the stack. I&#x27;m also
passionate about how developers and teams build software. &lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;Twitter: @fstephany&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;mailto:francois@tamere.eu&quot;&gt;Email: francois@tamere.eu&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;be.linkedin.com&#x2F;in&#x2F;fstephany&#x2F;&quot;&gt;LinkedIn&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Build a modern computer course on Coursera</title>
		<published>2017-03-08T15:00:00+00:00</published>
		<updated>2017-03-08T15:00:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2017-03-08-build-a-modern-computer-coursera-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2017-03-08-build-a-modern-computer-coursera-html/</id>
		<content type="html">&lt;p&gt;I don&#x27;t remember where I heard about this course but I don&#x27;t regret to have enrolled in &lt;a href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;learn&#x2F;build-a-computer&quot;&gt;Build a Modern Computer from First Principles: From Nand to Tetris&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a 6 week course on Coursera where you build a computer from the logical NAND gate to a fully working assembler. If you don&#x27;t know what a NAND gate is, don&#x27;t worry, the course explains in great lengths what they are and how they work. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-impressions&quot;&gt;General Impressions&lt;&#x2F;h2&gt;
&lt;p&gt;The course does not go into the actual physical implementation of the computer, that would probably need another 6 week course, but goes in the other direction and shows how abstractions are built on top of each other.&lt;&#x2F;p&gt;
&lt;p&gt;Soon enough you end up with a full assembler that outputs binary instructions that can be executed by your CPU. &lt;&#x2F;p&gt;
&lt;p&gt;I was a little bit disappointed by the way the ALU was introduced. The teachers basically gave the inner working of the ALU without any hint on how it was designed. They convinced the students that it was a simple and beautiful design but never explained how they ended up with it. Once again, I guess it is simply because the course is quit short and they only want to give an overview of the different parts.&lt;&#x2F;p&gt;
&lt;p&gt;I hold a master degree in Software Engineering but this course was a joy to follow. I guess I&#x27;m biased because I knew the concepts before but it is the first time that I grasp the hardware concepts that well. Diving into hardware was a really good trip and makes me want to know more about modern computer architecture. &lt;&#x2F;p&gt;
&lt;p&gt;I also made me want to dive into lower level languages (Rust, Assembler or even VHDL&#x2F;Verilog). I&#x27;ve always been attracted by the bare metal but have never jumped into it. Now seems to be a good time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;online-training&quot;&gt;Online training&lt;&#x2F;h2&gt;
&lt;p&gt;This course is the first that I followed online. Coursera has the notion of &amp;quot;end date&amp;quot; which is good for actually completing the course. I registered without thinking about my activities and obligations for the 6 weeks. That&#x27;s how I ended up moving (fortunately there is only 8km between the two houses), going on winter holidays with friends and continuing my Mandarin language class. While having a full time job. In retrospect, I  should have waited a little bit before taking the course.&lt;&#x2F;p&gt;
&lt;p&gt;I paid the 45€ as soon as I started. Not for the certificate (you can access the course for free if you don&#x27;t want&#x2F;need the certificate) but for the commitment. 
&#x2F;&#x2F;I paid for it so I shouldn&#x27;t procrastinate and finish this week&#x27;s assignment.&#x2F;&#x2F; is strong incentive to complete the course. Event if 45€ is not a huge amount of money by western standard, it puts value into the mix.&lt;&#x2F;p&gt;
&lt;p&gt;One of the drawback of online training is the lack of camaraderie between students. You never see the other participants and the online forums on Coursera are basically empty. I don&#x27;t know anyone in my entourage that was following the course. Having someone with who I could talk about the concepts and ideas explained in the course would have been great.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, it was a great experience and I&#x27;ll probably enroll for Andrew Ng&#x27;s course on machine learning :)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Android Things</title>
		<published>2016-12-29T15:00:00+00:00</published>
		<updated>2016-12-29T15:00:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2016-12-29-android-things-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2016-12-29-android-things-html/</id>
		<content type="html">&lt;p&gt;Google &lt;a href=&quot;https:&#x2F;&#x2F;developers.googleblog.com&#x2F;2016&#x2F;12&#x2F;announcing-googles-new-internet-of-things-platform-with-weave-and-android-things.html&quot;&gt;announced&lt;&#x2F;a&gt; the developer preview of &lt;em&gt;Android Things&lt;&#x2F;em&gt;. You have maybe heard about &lt;a href=&quot;https:&#x2F;&#x2F;www.wired.com&#x2F;2015&#x2F;05&#x2F;google-unveils-brillo-answer-smartifying-home&#x2F;&quot;&gt;Brillo&lt;&#x2F;a&gt; last year without knowing what it really was. The promise was so vague and abstract that nobody really cared (at least in my circles). With Android Things the promise is clearer. The big title on the project homepage says:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The ease and power of Android
If you can build an app, you can build a device&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It means that you can leverage your experience and tools to develop products. If you&#x27;ve already built android apps you&#x27;ll be at home. You can reuse Android Studio, reuse your existing Java code and deploy this to a device with or without a screen.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;good-enough&quot;&gt;Good enough&lt;&#x2F;h2&gt;
&lt;p&gt;But was is the difference with the myriad of other products in the market? It&#x27;s very easy to boot a Raspberry Pi, write some Python code and control the GPIOs to drive almost everything. The hobbyists already have all the tools they need to tinker and to build something useful.&lt;&#x2F;p&gt;
&lt;p&gt;When targeting Android Things, a developer can prototype on a board and easily deploy on another one. It seems that Google has certification process for Android Thing. Switching the underlying hardware and reuse the code is already possible with other OS of course but certified boards&#x2F;microprocessors could greatly improve the experience.&lt;&#x2F;p&gt;
&lt;p&gt;Unless an hobbyist is a hardcore android developer there is proably not a lot of reason to pick Android Thing for your next project. Setting up the Android SDK, learning Android Studio and all the associated tools (e.g., &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;command-line&#x2F;adb.html&quot;&gt;adb&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;command-line&#x2F;logcat.html&quot;&gt;logcat&lt;&#x2F;a&gt;) is not straightforward if you are doing it for the first time. It&#x27;s probably faster to connect a screen, keyboard and mouse on your Pi and start coding.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;updates&quot;&gt;Updates&lt;&#x2F;h2&gt;
&lt;p&gt;In an industrial setting the requirements are quite different. Processes are in place and you want to leverage battle tested tools. Products can have a very long lifetime, 10-20 years is common and you might need to mass produce them. If the business is not life critical, a Raspberry Pi and your code on it is probably enough. If the product is connected to the internet, you must be &lt;em&gt;much&lt;&#x2F;em&gt; more careful about what you do and you should have a transparent update mechanism to upgrade the device remotely. Beware that this update mechanism can also be abused to compromise the deployed devices. This really is a nightmare today.&lt;&#x2F;p&gt;
&lt;p&gt;In the eve of 2017, automatic and transparent updates are vital. This year, we&#x27;ve seen a lot of security issues from companies selling IoT devices in the fire and forget style. Consumers don&#x27;t realise that their connected lightbulbs, coffee maker and fridge are actually dangerous items that can be used in huge Denial of Service attack. Manufacturers have no incentives to level up their security and update practices.&lt;&#x2F;p&gt;
&lt;p&gt;Updating the OS running the devices is critical. Software companies are working hard to make this easier for developers and product manufacturers. For example, Canonical builds &lt;a href=&quot;https:&#x2F;&#x2F;developer.ubuntu.com&#x2F;en&#x2F;snappy&#x2F;&quot;&gt;Ubuntu Core&lt;&#x2F;a&gt; which provices a foundation on which products can be built. This is also where Android Things can shine. It is still vaporware but Google announced that they will provide the infrastructure to remotely update deployed devices. If done well, this could be a huge win as it would remove the burden that is currently imposed to product manufacturers. It also means that a product now relies on Google&#x27;s goodwill. If they shut down the service, you&#x27;re screwed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;locked-os&quot;&gt;Locked OS&lt;&#x2F;h2&gt;
&lt;p&gt;With Ubuntu Core, you have complete freedom over the OS. You can start a webserver, tune the processes that are started at startup, if you have some linux administration skills, you&#x27;ll be right at home. With Android, this is another story, as a user you have much less flexibility. The OS is made for phones&#x2F;tablet thus it is quite hard for apps to manipulate the system. On a phone, you don&#x27;t want third party app to touch the system. When a developer builds its own system, she wants to tune it exactly to fit her need. &lt;&#x2F;p&gt;
&lt;p&gt;Of course this is more dangerous but an IoT device does not have an app store. The code is loaded into it and then it should run forever (and get updates if it is connected to a network).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bare-metal&quot;&gt;Bare metal&lt;&#x2F;h2&gt;
&lt;p&gt;Now of course, all this only applies if:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The device does not need connectivity to the outside world, &lt;&#x2F;li&gt;
&lt;li&gt;The device does not need a full blown OS. Linux (or any non-specialized OS) brings a huge overhead: you need a more expensive and more power hungry processor and it&#x27;s harder to put the electronics in deep sleep mode. If realtime processing is a requirement, an OS might not be the best choice neither. &lt;&#x2F;li&gt;
&lt;li&gt;The device is life critical. That the software runs &lt;em&gt;on top&lt;&#x2F;em&gt; of a huge pile of software layers that the developer does not control. In life critical systems you need &lt;em&gt;strong&lt;&#x2F;em&gt; guarantees that the system handles failure. &lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In those situations a lightweight approach might be better. Something bare metal without an OS at all or with a specialized embedded one (e.g., FreeRTOS) will be more power efficient and cheaper to produce.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Android Things is trying to solve the same problem than Ubuntu Core (or other similar effort)&lt;&#x2F;li&gt;
&lt;li&gt;The first question when developing a product is whether or not you need full blown OS. Considering the following criteria:
&lt;ul&gt;
&lt;li&gt;Cost&lt;&#x2F;li&gt;
&lt;li&gt;Network connectivity (and thus security)&lt;&#x2F;li&gt;
&lt;li&gt;Updates (both the application code and the underlying system)&lt;&#x2F;li&gt;
&lt;li&gt;Realtime constraints&lt;&#x2F;li&gt;
&lt;li&gt;Lifetime&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We will see in the following months which hardware partners Google will have and which guarantees they will give with the update mechanism.&lt;&#x2F;p&gt;
&lt;p&gt;To me, Android Thing would be the killer OS if it was more moldable. There is not a lot of documentation on how to tune the system for a specific need. I guess this will come with time and experience. &lt;&#x2F;p&gt;
&lt;p&gt;Exciting times.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Android Google Study Jams Brussels Episode 2</title>
		<published>2015-03-10T23:00:00+00:00</published>
		<updated>2015-03-10T23:00:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2015-03-11-google-study-jam-week-6-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2015-03-11-google-study-jam-week-6-html/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2015&#x2F;android-codejam-brussels-3.jpg&quot; alt=&quot;audience at the Study Jam&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We are now at week 6 of the google study jam in Brussels. Things have been smooth so far. We are a core group of attendees with different backgrounds and goals, which is always nice.&lt;&#x2F;p&gt;
&lt;p&gt;This week&#x27;s lesson was about &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;guide&#x2F;topics&#x2F;providers&#x2F;content-providers.html&quot;&gt;Content Provider&lt;&#x2F;a&gt; and the URI concepts. Most of the questions were about the utility of this way of doing and we talked quite a lot about the different strategies to load data into an application.&lt;&#x2F;p&gt;
&lt;p&gt;Here are the links about the tools and libraries people have mentioned:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;greendao-orm.com&#x2F;&quot;&gt;greenDAO&lt;&#x2F;a&gt;, an ORM which adds a build step into the build process: you write a java program that runs on your computer and that generates your model classes with all the machinery to let you query them.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;emilsjolander&#x2F;sprinkles&quot;&gt;Sprinkles&lt;&#x2F;a&gt;, a lightweight library around SQLite. It provides a mapping with your model object throughout Java annotations. It&#x27;s quite simple to setup and does not hide the SQL complexity: you write your query by hand and it provides the object mapping. This is the one I currently use for my projects.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;novoda&#x2F;sqlite-analyzer&quot;&gt;sqlite-analyzer&lt;&#x2F;a&gt;, written by Novoda, it can generates Java code from sqlite migration&#x2F;databases. Pretty handy.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;novoda&#x2F;sqlite-provider&quot;&gt;sqlite-provider&lt;&#x2F;a&gt;, simplifies the use of sqlite with ContentProvider.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;BoD&#x2F;android-contentprovider-generator&quot;&gt;android-content-provider-generator&lt;&#x2F;a&gt;, mentioned by an attendee (hi &lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;IV3O&quot;&gt;Maxime&lt;&#x2F;a&gt;!), this library generates a ContentProvider from a JSON file that describes your model. &lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All in all, the most important lesson is that people should use what they&#x27;re comfortable with. Choosing a persistence strategy is something that you should think about. Using external libraries that are far from &lt;em&gt;the android way&lt;&#x2F;em&gt; of doing also conveys a certain risk (e.g., library maintenance).&lt;&#x2F;p&gt;
&lt;p&gt;We also had a question about how to do animations and how to read&#x2F;manipulate SVG objects. This is also a large topic but here are a few pointers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Romain Guy&#x27;s &lt;a href=&quot;http:&#x2F;&#x2F;www.curious-creature.com&#x2F;2013&#x2F;12&#x2F;21&#x2F;android-recipe-4-path-tracing&#x2F;&quot;&gt;blog post&lt;&#x2F;a&gt; about path tracing and SVG. The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;romainguy&#x2F;road-trip&quot;&gt;companion app&lt;&#x2F;a&gt; is something that you want to clone.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;bitbucket.org&#x2F;paullebeau&#x2F;androidsvg&#x2F;overview&quot;&gt;Android SVG&lt;&#x2F;a&gt; a library to manipulate SVG&lt;&#x2F;li&gt;
&lt;li&gt;Some blog post about animating the Toolbar while scrolling: &lt;a href=&quot;http:&#x2F;&#x2F;arnaud-camus.fr&#x2F;material-design-extended-toolbar-and-scrolling&#x2F;&quot;&gt;Arnaud Camus&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;mzgreen.github.io&#x2F;2015&#x2F;02&#x2F;15&#x2F;How-to-hideshow-Toolbar-when-list-is-scroling%28part1%29&#x2F;&quot;&gt;Michał Z&lt;&#x2F;a&gt;. Both have Github example projects.&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;strong&gt;very&lt;&#x2F;strong&gt; good &lt;a href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;dlew&#x2F;i-can-animate-and-so-can-you&quot;&gt;presentation by Daniel Lew&lt;&#x2F;a&gt; about all the different options you have to do animations on android. Some stuff are dated but it&#x27;s a good start.&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;http:&#x2F;&#x2F;android-developers.blogspot.be&#x2F;2011&#x2F;05&#x2F;introducing-viewpropertyanimator.html&quot;&gt;blog post&lt;&#x2F;a&gt; on the official Android developer blog about ViewPropertyAnimator.&lt;&#x2F;li&gt;
&lt;li&gt;There&#x27;s an app that aggregates a lot of open source library and most of them have demos. It&#x27;s quite nice if you need to find something: &lt;a href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.desarrollodroide.repos&quot;&gt;Libraries for Developers&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Once again, if you&#x27;re interested and want to participate, join the &lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;gdg-brussels&#x2F;&quot;&gt;Google Developer Group Brussels&lt;&#x2F;a&gt; on Meetup!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Android Google Study Jams Brussels</title>
		<published>2015-02-25T11:00:00+00:00</published>
		<updated>2015-02-25T11:00:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2015-02-25-google-study-jam-week2-notes-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2015-02-25-google-study-jam-week2-notes-html/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2015&#x2F;android-codejam-brussels-1.jpg&quot; alt=&quot;audience at the Study Jam&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;developerstudyjams.com&#x2F;&quot;&gt;Google Developer Study Jams Android Fundamentals&lt;&#x2F;a&gt; is a worldwide study group organised by Google and Udacity. The principle is quite simple: people follows an online course on Udacity to become Android developers. Events are locally organized weekly so participants can share their problems, ideas and solutions.&lt;&#x2F;p&gt;
&lt;p&gt;The official website describes it perfectly:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Study Jams are an opportunity for students to receive free, in-person guidance and tutoring on the Udacity course in a fun classroom environment. Study Jam sessions are designed around the Udacity course structure, with a weekly session following each lesson (6 lessons), plus two additional weeks for completing and sharing course final projects. Students are expected to come to the Study Jam sessions having completed that week’s Udacity lesson online, so that the Study Jam time may be used to review key concepts, address questions, and work on individual projects. The live community atmosphere and tutoring is designed to help students achieve deeper learning around the concepts taught in the course.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;gdg-brussels&quot;&gt;Google Developer Group of Brussels&lt;&#x2F;a&gt; is organising the local event in Belgium in the beautiful working space &lt;a href=&quot;http:&#x2F;&#x2F;co-station.com&#x2F;wrkcafe&#x2F;&quot;&gt;Co.Station&lt;&#x2F;a&gt;, next to the central station.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;gdg-brussels&#x2F;members&#x2F;9160265&#x2F;&quot;&gt;Friedger Müffke&lt;&#x2F;a&gt; and I are the two tutors for the Brussels local group. We try to expand the content of the online course with some of our experiences. We also try to give the student a feeling of the Android ecosystem. &lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2015&#x2F;android-codejam-brussels-2.jpg&quot; alt=&quot;audience at the Study Jam&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Android fondamental course does not use any external libraries. Even for HTTP calls. Instead they ask the students to copy&#x2F;paste a huge gist containing the code doing the call. I thought that it would have been nice to show the students how to include an external library.&lt;&#x2F;p&gt;
&lt;p&gt;We started to follow that path and we talked quite a lot about libraries that I find useful. Here are some of them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;square.github.io&#x2F;okhttp&#x2F;&quot;&gt;OkHTTP&lt;&#x2F;a&gt;, HTTP calls should be easy.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;google-gson&#x2F;&quot;&gt;GSON&lt;&#x2F;a&gt;, JSON manipulation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;square.github.io&#x2F;retrofit&#x2F;&quot;&gt;Retrofit&lt;&#x2F;a&gt;, Ideal if you want to interact with a REST+JSON webservice. Beware that it can feel a little bit &lt;em&gt;magic&lt;&#x2F;em&gt;, it&#x27;s hard to know what&#x27;s going on. It relies on OkHTTP and GSON to do its job.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;greenrobot&#x2F;EventBus&quot;&gt;EventBus&lt;&#x2F;a&gt;, an EventBus for your application. It lets you send event throughout your application. 
*&lt;a href=&quot;https:&#x2F;&#x2F;square.github.io&#x2F;otto&#x2F;&quot;&gt;Otto&lt;&#x2F;a&gt;, basically the same as EventBus. Try both and keep the one you prefer.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JakeWharton&#x2F;timber&quot;&gt;Timber&lt;&#x2F;a&gt;, small librarie that makes it easier to deal with logs. &lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can find all those library in the &lt;a href=&quot;https:&#x2F;&#x2F;bintray.com&#x2F;bintray&#x2F;jcenter&quot;&gt;jcenter maven repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Many of those libraries are edited by Square. Check their &lt;a href=&quot;https:&#x2F;&#x2F;square.github.io&#x2F;&quot;&gt;open source listing&lt;&#x2F;a&gt; for more goodness.&lt;&#x2F;p&gt;
&lt;p&gt;Another small tool that we covered (but that I haven&#x27;t tested in real life yet) is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orfjackal&#x2F;retrolambda&quot;&gt;Retrolambda&lt;&#x2F;a&gt;. You integrate it into your build chain and it lets you write lambda expressions with java 7. Nobody knows when (or even if) Java 8 will be available on android, so this tool can come handy if you really want to use those lambdas.&lt;&#x2F;p&gt;
&lt;p&gt;We also mentioned &lt;a href=&quot;https:&#x2F;&#x2F;www.genymotion.com&quot;&gt;Genymotion&lt;&#x2F;a&gt;, a fast android emulator based on VirtualBox.&lt;&#x2F;p&gt;
&lt;p&gt;Someone has a question about &lt;code&gt;Context&lt;&#x2F;code&gt; last week. &lt;a href=&quot;http:&#x2F;&#x2F;possiblemobile.com&#x2F;2013&#x2F;06&#x2F;context&#x2F;&quot;&gt;This article&lt;&#x2F;a&gt; is quite good to grasp the differences between the different available contexts.&lt;&#x2F;p&gt;
&lt;p&gt;Last but not least, we talked about &lt;a href=&quot;http:&#x2F;&#x2F;androidweekly.net&#x2F;&quot;&gt;Android Weekly&lt;&#x2F;a&gt;, a very nice newsletter that collects all the news from the Android ecosytem. It is a great way to discover new libraries and tools. &lt;&#x2F;p&gt;
&lt;p&gt;Thanks a lot to &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;DianeLanterman&quot;&gt;Anne Collet&lt;&#x2F;a&gt; from &lt;a href=&quot;http:&#x2F;&#x2F;www.lewagon.org&#x2F;brussels&quot;&gt;Le Wagon Brussels&lt;&#x2F;a&gt; to host us in Co.Station.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re interested and want to participate, join the &lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;gdg-brussels&#x2F;&quot;&gt;Google Developer Group Brussels&lt;&#x2F;a&gt; on Meetup!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Dependency injection with Dagger</title>
		<published>2015-01-13T16:48:00+00:00</published>
		<updated>2015-01-13T16:48:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2015-01-13-dependency-injection-dagger-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2015-01-13-dependency-injection-dagger-html/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dependency_injection&quot;&gt;Dependency injection&lt;&#x2F;a&gt; (or DI) is quite a big topic in object oriented design. It can be quite hard to grasp for junior developers but it is a pattern that should be in your toolbox.&lt;&#x2F;p&gt;
&lt;p&gt;This small blog post will briefly show you how to use &lt;a href=&quot;https:&#x2F;&#x2F;square.github.io&#x2F;dagger&#x2F;&quot;&gt;Dagger&lt;&#x2F;a&gt;, a common DI framework in the Android world.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;android-example&quot;&gt;Android Example&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JakeWharton&#x2F;u2020&quot;&gt;Jake Wharton&#x27;s u2020&lt;&#x2F;a&gt; is an Android app showcasing the use of dependency injection using Dagger.&lt;&#x2F;p&gt;
&lt;p&gt;The app is full of great tips but taken together, they can be a bit overwhelming if you just want to learn the framework. The injection depends on the variant of the app: the &lt;code&gt;debug&lt;&#x2F;code&gt; version have a completely different layout that includes a debug drawer. It is a great learning app but you probably don&#x27;t want to deal with all that complexity when you just want to learn how Dagger works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;our-app-inject-an-webview-url-at-runtime&quot;&gt;Our app: Inject an Webview url at runtime&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2015&#x2F;dagger-screen.jpg&quot; alt=&quot;The Webview displaying Bing and Yahoo search&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate the DI, we will change the url displayed by a webview at runtime. Change &lt;em&gt;url&lt;&#x2F;em&gt; by &lt;em&gt;endpoint&lt;&#x2F;em&gt; and &lt;em&gt;webview&lt;&#x2F;em&gt; by &lt;em&gt;API&lt;&#x2F;em&gt; and you&#x27;ll have a very common scheme in Mobile apps. This can be useful if you want to switch between your testing and staging servers to test that everything is working.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we&#x27;ll see how we can dynamically change the endpoint our app is talking to. Beware that it could become dangerous in a real application: dynamically changing the endpoint at runtime is not a good idea if you have a session on the server or if you use a local database to synchronise data with the backend. You can easily meangle all your data and send inconsistent requests to the server.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;dagger-example&quot;&gt;Our app&lt;&#x2F;a&gt; will be very simple: a webview and radio buttons. The webview will display &lt;em&gt;Yahoo&lt;&#x2F;em&gt; or &lt;em&gt;Bing&lt;&#x2F;em&gt; according to the currently selected radio button.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;annotations&quot;&gt;Annotations&lt;&#x2F;h2&gt;
&lt;p&gt;This app shows three very simple annotations of Dagger: &lt;code&gt;@Inject&lt;&#x2F;code&gt;, &lt;code&gt;@Provides&lt;&#x2F;code&gt; and &lt;code&gt;@Module&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;inject-on-a-field&quot;&gt;&lt;code&gt;@Inject&lt;&#x2F;code&gt; (on a field)&lt;&#x2F;h3&gt;
&lt;p&gt;This annotation shows that you want to inject a value in this field. We will see later when values are injected.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;provides-on-a-method&quot;&gt;&lt;code&gt;@Provides&lt;&#x2F;code&gt; (on a method)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;@Provides&lt;&#x2F;code&gt; shows that the annotated method can provide a value. Provider methods are part of a Module.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;module-on-a-class&quot;&gt;&lt;code&gt;@Module&lt;&#x2F;code&gt; (on a class)&lt;&#x2F;h3&gt;
&lt;p&gt;A module is the entry point of the injection. We will build our object graph with a Set of modules. We then inject objects that have injectable fields into this object graph to get them populated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;code&quot;&gt;Code&lt;&#x2F;h2&gt;
&lt;p&gt;The app has two modules, &lt;code&gt;BingEndPointModule&lt;&#x2F;code&gt; and &lt;code&gt;YahooEndPointModule&lt;&#x2F;code&gt;. Those are injected at runtime when you choose Bing and Yahoo in the UI.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;@Module(injects = { MainActivity.class })
&lt;&#x2F;span&gt;&lt;span&gt;public class BingEndpointModule {
&lt;&#x2F;span&gt;&lt;span&gt;    @Provides
&lt;&#x2F;span&gt;&lt;span&gt;    Endpoint provideEndpoint() {
&lt;&#x2F;span&gt;&lt;span&gt;      return new Endpoint(&amp;quot;http:&#x2F;&#x2F;bing.com&#x2F;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the &lt;code&gt;@Module&lt;&#x2F;code&gt; annotation, you can notice that you have to provide where this module will be injected. Dagger verify at compile time that you haven&#x27;t messed up.&lt;&#x2F;p&gt;
&lt;p&gt;In the main activity, we wrote a simple method to switch:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;private void updateModule(Object module) {
&lt;&#x2F;span&gt;&lt;span&gt;    objectGraph = ObjectGraph.create(module);
&lt;&#x2F;span&gt;&lt;span&gt;    objectGraph.inject(this);
&lt;&#x2F;span&gt;&lt;span&gt;    refreshWebview();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which is called when we change the selection of the RadioGroup:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;private void selectBing() {
&lt;&#x2F;span&gt;&lt;span&gt;    updateModule(new BingEndpointModule());
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you see, there is nothing really fancy in this code. I wouldn&#x27;t use Dagger for such a simple case in practice but keeping it small helps to identify the key parts of Dagger.&lt;&#x2F;p&gt;
&lt;p&gt;You can get the whole source code on the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;dagger-example&quot;&gt;Github repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;&#x2F;h2&gt;
&lt;p&gt;That was short. Once again, you should clone &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JakeWharton&#x2F;u2020&quot;&gt;u2020&lt;&#x2F;a&gt; and study its source code. It shows quite a lot in a condensed app.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo packages to know</title>
		<published>2014-06-02T00:08:00+00:00</published>
		<updated>2014-06-02T00:08:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2014-06-02-pharo-package-to-know-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2014-06-02-pharo-package-to-know-html/</id>
		<content type="html">&lt;p&gt;Starting to work with Pharo Smalltalk these days is quite a non trivial process. Non-smalltalkers are already lost with the language and the environment. On top of that, they must learn tools and library names that are quite specific to Smalltalk or Pharo.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s my short list of project name to know:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morphic&lt;&#x2F;strong&gt;: The GUI layer of Pharo. It is not really&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http:&#x2F;&#x2F;spec.st&#x2F;&quot;&gt;Spec&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: A framework to describe user interfaces. It powers quite a few tools in the Pharo environment. At the moment, it uses Morphic as the backend but it should eventually be backend-agnostic.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nautilus&lt;&#x2F;strong&gt;: The code browser. It&#x27;s the primary tool to interact with your code.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http:&#x2F;&#x2F;zn.stfx.eu&#x2F;zn&#x2F;index.html&quot;&gt;Zinc&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: an HTTP client and server library integrated into Pharo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Monticello&lt;&#x2F;strong&gt;: A source control (think Git but specialized for Smalltalk packages) dedicated to Smalltalk. It outputs &lt;code&gt;.mcz&lt;&#x2F;code&gt; packages that contain the whole source code for a given version. &lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Gofer&lt;&#x2F;strong&gt;: A tool helping you to grab Monticello packages. It can be used to script the loading of Monticello Package&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Metacello&lt;&#x2F;strong&gt;: A tool to express the dependencies for your project. Think Bundler, Maven or Pip for Smalltalk. You usually grab the MetacelloConfiguration of a package with Gofer and then ask the configuration to load the project.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Versionner&lt;&#x2F;strong&gt;: A Graphical tool to help you create your Metacello configurations.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Athens&lt;&#x2F;strong&gt;: A new vectorial backend for Pharo. It will eventually replace the current rendering engine. It is based on Cairo.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;NativeBoost&lt;&#x2F;strong&gt;: A library to call C libraries from Pharo. Other projects exist (e.g., FFI, Mars) but NativeBoost (NB) is probably the way to go for new projects.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Filetree&lt;&#x2F;strong&gt;: Filetree lets you write Monticello packages into the regular filesystem. If you want to use git, this is the way to go. There are efforts to use git natively with the tools available in the image (e.g., gitfiletree).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There a many more but those are probably the core packages that a newcomer will hear about when (s)he starts to play with Pharo.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve linked some of the projects to their homepage but all the others should be covered by &lt;a href=&quot;https:&#x2F;&#x2F;ci.inria.fr&#x2F;pharo-contribution&#x2F;job&#x2F;DeepIntoPharo&#x2F;lastSuccessfulBuild&#x2F;artifact&#x2F;tmp&#x2F;&quot;&gt;Deep into Pharo&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;ci.inria.fr&#x2F;pharo-contribution&#x2F;job&#x2F;PharoForTheEnterprise&#x2F;lastSuccessfulBuild&#x2F;artifact&#x2F;&quot;&gt;Pharo For the Entreprise&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ping me on &lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;Twitter&lt;&#x2F;a&gt; if I forgot an important package that does not have a meaningful name. &lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>iOS legacy code</title>
		<published>2013-10-26T16:40:00+00:00</published>
		<updated>2013-10-26T16:40:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2013-10-26-ios-legacy-code-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2013-10-26-ios-legacy-code-html/</id>
		<content type="html">&lt;p&gt;Confession: I &lt;strong&gt;love&lt;&#x2F;strong&gt; dealing with legacy code. I love to curse when reading source code. I love to refactor all those defects that make my eyes bleed.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, I describe some smells that I often see when taking over or assessing iOS apps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code duplication&lt;&#x2F;strong&gt;. Copy&#x2F;Pasting a snippet of code from time to time is OK. Copying the same 60 lines in almost all your &lt;code&gt;ViewController&lt;&#x2F;code&gt; is definitely bad.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Naming convention&lt;&#x2F;strong&gt;. The use of singular and plural should not be incidental. It brings clarity to your code. Do not start methods name with a capital letter. Use meaningful variable names. Objective-C is verbose &lt;em&gt;because&lt;&#x2F;em&gt; people express everything in the naming. Don&#x27;t break that.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Indentation and whitespace&lt;&#x2F;strong&gt;. This is at a microscopic level but you should have a consistent coding style. Always pout your opening brackets at the same place, separate your methods definition by one empty line, etc. Those are simple rules but helps to read your source code.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Magic constants&lt;&#x2F;strong&gt;. The return codes are obscure. If you really want to identify errors with error codes, at least create constants so the reader knows what you mean by &lt;em&gt;Error 42&lt;&#x2F;em&gt;. &lt;code&gt;NSError&lt;&#x2F;code&gt; is made for this, do not go with your own solution that works half of the time.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Data Modeling&lt;&#x2F;strong&gt;. Use your custom ORM only in specific cases. Apple provides a good framework that everybody knows and uses: &lt;em&gt;CoreData&lt;&#x2F;em&gt;. It is a huge and complex piece of software but it can handle almost every situation and is battle tested.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Code clarity&lt;&#x2F;strong&gt;. You should always express the same concept with the same code structure. For example a screen showing a note should have a variable called &lt;code&gt;currentNote&lt;&#x2F;code&gt;representing the note currently displayed. And not an array containing all the notes with another variable telling the index of the current note in the array. It confuses the reader. If you go that way, you must explain the reason in concise comments.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Properties vs Instance variable&lt;&#x2F;strong&gt;. Use one or the other but do not mix them without any reasons. As a side notes, accessors&#x2F;mutators are generated for you. Do not replicate your Java habits in here.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Objective-C&lt;&#x2F;strong&gt;. Obj-C has improved over time to make it easier to read, easier to write. The new features tend to make it easier to remove the boilerplate of the code. (&lt;code&gt;@&lt;&#x2F;code&gt; notation, auto-synthesize properties, etc). Know the language you are using.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Custom UI&lt;&#x2F;strong&gt;. Two simple rules :
&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;appearance proxies&lt;&#x2F;code&gt; if you want to the same component all over the app.&lt;&#x2F;li&gt;
&lt;li&gt;Do not use magic constants for sizes and frames. If Apple changes the screen for the iPhone 6, you&#x27;ll get screwed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Certificate&lt;&#x2F;strong&gt;. Always use the signing certificate of your clients. If they don&#x27;t know how to create it, generate it &lt;em&gt;with&lt;&#x2F;em&gt; them, not &lt;em&gt;for&lt;&#x2F;em&gt; them. The certificates control everything for publishing apps. If your clients are not happy with you, you should let them go.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Arc&lt;&#x2F;strong&gt;. Use arc. You do not want to manage your memory by hand. The cases where the compiler gets it wrong are incredibly rare.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;post-mortem&quot;&gt;Post-mortem&lt;&#x2F;h2&gt;
&lt;p&gt;Those notes are quite broken and do not follow any logic, I&#x27;ve copy-pasted some snippets from some projects I&#x27;ve helped to assess.&lt;&#x2F;p&gt;
&lt;p&gt;I suck at editing, do not expect this blog post to be a complete, clean and accurate report of defects in iOS Code. It covers stuff at the code snippet level; there is more to tell about architecture of apps but the subject is too broad for this rant.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;uiviewcontroller-ui-tuning&quot;&gt;UIViewController &amp;amp; UI Tuning&lt;&#x2F;h3&gt;
&lt;p&gt;Almost every single ViewController starts with the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;)initWithNibName:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSString &lt;&#x2F;span&gt;&lt;span&gt;*)nibNameOrNil bundle:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSBundle &lt;&#x2F;span&gt;&lt;span&gt;*)nibBundleOrNil
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span&gt;= [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;initWithNibName:&lt;&#x2F;span&gt;&lt;span&gt;nibNameOrNil &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;bundle:&lt;&#x2F;span&gt;&lt;span&gt;nibBundleOrNil];
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Custom initialization
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)viewWillAppear:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;BOOL&lt;&#x2F;span&gt;&lt;span&gt;)animated{
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;viewWillAppear:&lt;&#x2F;span&gt;&lt;span&gt;animated];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;loadApparence&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What&#x27;s wrong with this:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The first method is useless. Why keep the cruft if you don&#x27;t need it.&lt;&#x2F;li&gt;
&lt;li&gt;Whitespace boy. One empty line between the methods is all I ask.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Ok. Let&#x27;s have a look at &lt;code&gt;loadApparence&lt;&#x2F;code&gt;. I&#x27;m gonna split it to make it easier to read.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) loadApparence
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	[[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;] setNavigationBarHidden:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationBar&lt;&#x2F;span&gt;&lt;span&gt; setTintColor:[UIColor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;grayColor&lt;&#x2F;span&gt;&lt;span&gt;]];
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationBar&lt;&#x2F;span&gt;&lt;span&gt; respondsToSelector:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@selector(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:forBarMetrics:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;	{
&lt;&#x2F;span&gt;&lt;span&gt;		[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationBar 
&lt;&#x2F;span&gt;&lt;span&gt;			setBackgroundImage:[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bg_Navigation_Header.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] 
&lt;&#x2F;span&gt;&lt;span&gt;			forBarMetrics:UIBarMetricsDefault];
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationBar&lt;&#x2F;span&gt;&lt;span&gt; respondsToSelector:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@selector(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitleTextAttributes:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;	{
&lt;&#x2F;span&gt;&lt;span&gt;		[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationBar&lt;&#x2F;span&gt;&lt;span&gt; setTitleTextAttributes:
&lt;&#x2F;span&gt;&lt;span&gt;			[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSDictionary &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;dictionaryWithObjectsAndKeys:&lt;&#x2F;span&gt;&lt;span&gt;[UIColor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;navigationTitleTextColor&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;			UITextAttributeTextColor,
&lt;&#x2F;span&gt;&lt;span&gt;			[UIColor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;colorWithRed:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;green:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;blue:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alpha:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;			UITextAttributeTextShadowColor,
&lt;&#x2F;span&gt;&lt;span&gt;			[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;NSValue &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;valueWithUIOffset:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;UIOffsetMake&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)],
&lt;&#x2F;span&gt;&lt;span&gt;			UITextAttributeTextShadowOffset,
&lt;&#x2F;span&gt;&lt;span&gt;			[UIFont &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;fontWithName:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Klavika-Medium&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;size:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22.0&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;			UITextAttributeFont,
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;]];
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	…
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mmmm. At first sight:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;- (void) loadApparence&lt;&#x2F;code&gt;. French developer spotted.&lt;&#x2F;li&gt;
&lt;li&gt;I know that it&#x27;s sometimes hard in Objective-C&#x2F;Cocoa but the 80 caracter wide rules should be enforced when possible. Not everyone codes fullscreen on a 27&#x27;&#x27; monitor.&lt;&#x2F;li&gt;
&lt;li&gt;I always worry when I see &lt;code&gt;respondsToSelector:&lt;&#x2F;code&gt;. It usually means that the developer has missed some object-oriented polymorphism. In this case it looks like he is checking that the navigation bar has all the capabilities it is supposed to have. Maybe because of API changes in the UINavigationController? A comment would have been welcome.&lt;&#x2F;li&gt;
&lt;li&gt;Changing the navigation bar background. I bet this happens everywhere in the project. BINGO, after a quick search, the line &lt;code&gt;[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@&amp;quot;bg_Navigation_Header.png&amp;quot;] forBarMetrics:UIBarMetricsDefault];&lt;&#x2F;code&gt; appears 22 times in the project.  This code has been copy&#x2F;pasted everywhere. Why not use the &lt;em&gt;appearance proxy&lt;&#x2F;em&gt;  of externalise this code if you compile under iOS 5 (is there anyone still using iOS &amp;lt; 5 in 2013?)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;dictionaryWithObjectsAndKeys:&lt;&#x2F;code&gt;? Really? The &lt;code&gt;@&lt;&#x2F;code&gt; notation should be used everywhere.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;UIButton *buttonSave = [UIButton &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;buttonWithType:&lt;&#x2F;span&gt;&lt;span&gt;UIButtonTypeCustom];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_blue_normal.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateNormal];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_blue_pressed.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlEventTouchUpInside];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_blue_pressed.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateHighlighted];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;titleLabel&lt;&#x2F;span&gt;&lt;span&gt; setFont:[UIFont &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;fontWithName: &lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Custom-Medium&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;size:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setFrame:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CGRectMake&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;44&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;)];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitleEdgeInsets:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;UIEdgeInsetsMake&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setHighlighted:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;addTarget:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;action:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@selector(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;save:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forControlEvents:&lt;&#x2F;span&gt;&lt;span&gt;UIControlEventTouchUpInside];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonSave &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitle:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;myFunkyLocalizeFunction&lt;&#x2F;span&gt;&lt;span&gt;(@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Save&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateNormal];
&lt;&#x2F;span&gt;&lt;span&gt;UIBarButtonItem *saveButton = [[[UIBarButtonItem &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;] initWithCustomView:buttonSave] autorelease];
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;navigationItem&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rightBarButtonItem &lt;&#x2F;span&gt;&lt;span&gt;= saveButton;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;UIButton *buttonCancel = [UIButton &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;buttonWithType:&lt;&#x2F;span&gt;&lt;span&gt;UIButtonTypeCustom];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_grey_normal.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateNormal];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_grey_pressed.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlEventTouchUpInside];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setBackgroundImage:&lt;&#x2F;span&gt;&lt;span&gt;[UIImage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;imageNamed:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;btn_grey_pressed.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateHighlighted];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;titleLabel&lt;&#x2F;span&gt;&lt;span&gt; setFont:[UIFont &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;fontWithName: &lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Custom-Medium&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;size:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setFrame:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CGRectMake&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;60&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;)];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitleEdgeInsets:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;UIEdgeInsetsMake&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setHighlighted:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;addTarget:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;action:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@selector(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;cancel:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forControlEvents:&lt;&#x2F;span&gt;&lt;span&gt;UIControlEventTouchUpInside];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitle:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;myFunkyLocalizeFunction&lt;&#x2F;span&gt;&lt;span&gt;(@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Cancel&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateNormal];
&lt;&#x2F;span&gt;&lt;span&gt;[buttonCancel &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;setTitleColor:&lt;&#x2F;span&gt;&lt;span&gt;[UIColor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;colorWithRed:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.5 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;green:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.52 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;blue:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.57 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alpha:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;forState:&lt;&#x2F;span&gt;&lt;span&gt;UIControlStateNormal] ;
&lt;&#x2F;span&gt;&lt;span&gt;UIBarButtonItem *cancelBtBar = [[[UIBarButtonItem &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;] initWithCustomView:buttonCancel]autorelease];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;This snippet has been copy&#x2F;pasted everywhere the save and cancel button are neded.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[UIFont fontWithName: @&amp;quot;Custom-Medium&amp;quot; size:16]]&lt;&#x2F;code&gt; is everywhere.&lt;&#x2F;li&gt;
&lt;li&gt;The experienced eye will have noticed that &lt;code&gt;[buttonSave setBackgroundImage:[UIImage imageNamed:@&amp;quot;btn_blue_pressed.png&amp;quot;] forState:UIControlEventTouchUpInside];&lt;&#x2F;code&gt; will generate the warning &lt;em&gt;&amp;quot;Implicit conversion from enumeration type &#x27;enum UIControlEvents&#x27; to different enumeration type &#x27;UIControlState&#x27; (aka &#x27;enum UIControlState&#x27;)&amp;quot;&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;return-codes&quot;&gt;Return codes&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(([description &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isEqualToString:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;DELETE_NOTE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;])&amp;amp;&amp;amp;([targetType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isEqualToString:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FOLDER&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	XXXFolder *folder = [[XXXFolder &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;] initWithDictionnary:[adic &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;objectForKey:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]];
&lt;&#x2F;span&gt;&lt;span&gt;	XXXNote *note = [[XXXNote &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;] initWithDictionnary:[[adic &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;objectForKey:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] objectForKey:@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;note&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]];
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;((folder)&amp;amp;&amp;amp;(note))
&lt;&#x2F;span&gt;&lt;span&gt;	{
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects &lt;&#x2F;span&gt;&lt;span&gt;= [[[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSDictionary &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;] initWithObjects:@[folder, note] forKeys:@[@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;folder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, @&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;note&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]] autorelease];
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Does anybody knows what the return code 20 means? I do not have a clue. The other parts of the &lt;code&gt;if&lt;&#x2F;code&gt; (and there are 13 consecutive &lt;code&gt;if&lt;&#x2F;code&gt; clauses) return a different code.&lt;&#x2F;p&gt;
&lt;p&gt;That line mixing two syntax is particularly cool. The array is declared the new way while the dictionary is declared the old school way (it was a one liner, I idented it to make it more readable):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects &lt;&#x2F;span&gt;&lt;span&gt;= [[[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSDictionary &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;	initWithObjects:@[folder, note]
&lt;&#x2F;span&gt;&lt;span&gt;	forKeys:@[@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;folder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, @&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;note&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]] autorelease];`
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;while they could have used:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects &lt;&#x2F;span&gt;&lt;span&gt;= @{ @&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;folder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:folder,
&lt;&#x2F;span&gt;&lt;span&gt;				@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;note&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:note };
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or even:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;	self.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;objects &lt;&#x2F;span&gt;&lt;span&gt;= NSDictionaryOfVariableBindings(folder, note);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;mixing-properties-and-instance-variables&quot;&gt;Mixing Properties and instance variables&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@interface &lt;&#x2F;span&gt;&lt;span&gt;XXXNoteDetailViewController &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;UIViewController &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UITextFieldDelegate, UITextViewDelegate&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	SoundEffect *player;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *addTaskButton;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *connectToFolderButton;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *shareNoteButton;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *editTaskButton;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *deleteNoteButton;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIView *controlBarView;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIButton *commentsButton;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@property &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;retain&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;nonatomic&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;IBOutlet&lt;&#x2F;span&gt;&lt;span&gt; UIImageView *photoImageView;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; And 21 more properties for UI elements.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pick one approach and stick with it. Don&#x27;t mix them without reason.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;meta-programming&quot;&gt;Meta programming&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)viewDidLoad {
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Do any additional setup after loading the view from its nib.
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;performSelector:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;@selector(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;loadNote&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m still wondering why the &lt;code&gt;performSelector:&lt;&#x2F;code&gt; is there. Isn&#x27;t&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)viewDidLoad {
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;	[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;loadNote&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;easier to read?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;properties&quot;&gt;Properties&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;XXXNoteDetailViewController&lt;&#x2F;code&gt; displays a note. Why does it need to keep a whole &lt;code&gt;notes&lt;&#x2F;code&gt; array and a property called &lt;code&gt;ind&lt;&#x2F;code&gt; to hold the index of the note to display? &lt;code&gt;notes&lt;&#x2F;code&gt; is never used. Except to retrieve the
note to display. Many methods start with: &lt;code&gt;Note *note = [notes objectAtIndex:ind];&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Oh oh no, it&#x27;s used when the user deletes the currently displayed note:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;	[notes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;removeObjectAtIndex:&lt;&#x2F;span&gt;&lt;span&gt;ind];
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;([notes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;] &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        ind--;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(ind &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;&amp;amp;&amp;amp; ind &amp;lt; [notes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;]) {
&lt;&#x2F;span&gt;&lt;span&gt;            [notes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;objectAtIndex:&lt;&#x2F;span&gt;&lt;span&gt;ind];
&lt;&#x2F;span&gt;&lt;span&gt;        } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            ind = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            [notes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;objectAtIndex:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        [[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;navigationController&lt;&#x2F;span&gt;&lt;span&gt;] popViewControllerAnimated:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;YES&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ouch.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;java-ite&quot;&gt;Java-ite&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;@&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;property &lt;&#x2F;span&gt;&lt;span&gt;(nonatomic, retain, setter = setContent:, getter = getContent) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSString &lt;&#x2F;span&gt;&lt;span&gt;*content;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Accessors are generated for properties, do not try to make it look like Java.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ifs&quot;&gt;Ifs&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;currentNote&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(![[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSFileManager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;defaultManager&lt;&#x2F;span&gt;&lt;span&gt;] fileExistsAtPath:fullPath])
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;NSLog&lt;&#x2F;span&gt;&lt;span&gt;(@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;fichier inexistant : &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%@&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, fullPath);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; [[SoundManager getInstance] playSoundFromPath:fullPath];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;([player &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;loadContentsOfFile:&lt;&#x2F;span&gt;&lt;span&gt;fullPath])
&lt;&#x2F;span&gt;&lt;span&gt;	{
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;NSLog&lt;&#x2F;span&gt;&lt;span&gt;(@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;playing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%@&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, fullPath);
&lt;&#x2F;span&gt;&lt;span&gt;		[player &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;play&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;NSLog&lt;&#x2F;span&gt;&lt;span&gt;(@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;impossible de lire le fichier : &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%@&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, fullPath);
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This if clause probably violates all the good practices you&#x27;ve ever learned for conditions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;whitespace&quot;&gt;Whitespace&lt;&#x2F;h3&gt;
&lt;p&gt;Method declaration identation is quite funky (white space preserved):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSDictionary &lt;&#x2F;span&gt;&lt;span&gt;*)dicValue;
&lt;&#x2F;span&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;)initWithContentArray:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSMutableArray&lt;&#x2F;span&gt;&lt;span&gt;*)acontentArray;
&lt;&#x2F;span&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;)initWithDictionnary:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSDictionary&lt;&#x2F;span&gt;&lt;span&gt;*)adic;
&lt;&#x2F;span&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) addEmails:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSString &lt;&#x2F;span&gt;&lt;span&gt;*)emails;
&lt;&#x2F;span&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)save;
&lt;&#x2F;span&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) setShareEmailsWithArray:(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSArray &lt;&#x2F;span&gt;&lt;span&gt;*)shareEmails;
&lt;&#x2F;span&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;NSArray &lt;&#x2F;span&gt;&lt;span&gt;*)getShareEmailsArray;
&lt;&#x2F;span&gt;&lt;span&gt;-(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;BOOL&lt;&#x2F;span&gt;&lt;span&gt;) isOwner;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One empty line between method declaration should be the norm.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;managing-database&quot;&gt;Managing database&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;	[dataBaseManager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;registerAndGetQueryResult:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;INSERT OR REPLACE INTO tasks (id, description, date_creation, complete, date_complete, due_date, alarm_date, id_note, updatedate, tosend, ownerid, shareemails) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?,?)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;withParams:&lt;&#x2F;span&gt;&lt;span&gt;@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%@%@%@%d%@%@%@%@%@%@&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;identifier&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;description&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dateCreation&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;isComplete&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dateComplete&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dueDate&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;alarmDate&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;idNote&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;updateDate&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ownerId&lt;&#x2F;span&gt;&lt;span&gt;, task.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;shareEmails&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All the database interaction is made in pure SQL. A custom in-house framework is used to manage all the queries&#x2F;inserts&#x2F;updates. Why not go with CoreData ? It&#x27;s the standard on iOS and contains everything a developer need. It&#x27;s a bit complex at first but it can save a lot of time afterwards.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;magic-constants&quot;&gt;Magic constants&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;- (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) showItemWithItem:(XXXTimelineItem *)timelineItem
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;switch &lt;&#x2F;span&gt;&lt;span&gt;(timelineItem.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;			[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;showTodo&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;			[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;showFolderWithItem:&lt;&#x2F;span&gt;&lt;span&gt;timelineItem];
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;			[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;showNoteWithItem:&lt;&#x2F;span&gt;&lt;span&gt;timelineItem];
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;string-typing&quot;&gt;String typing&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;objective-c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-objective-c &quot;&gt;&lt;code class=&quot;language-objective-c&quot; data-lang=&quot;objective-c&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;currentNote&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;getType&lt;&#x2F;span&gt;&lt;span&gt; isEqualToString:@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;TEXT&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]) {…}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;currentNote&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;getType&lt;&#x2F;span&gt;&lt;span&gt; isEqualToString:@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PHOTO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]) {…}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;currentNote&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;getType&lt;&#x2F;span&gt;&lt;span&gt; isEqualToString:@&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;AUDIO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]) {…}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ouch.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;libraries&quot;&gt;Libraries&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;CocoaPods&lt;&#x2F;em&gt; is the way to go to manage libraries.&lt;&#x2F;p&gt;
&lt;p&gt;The projects has Stig Brautaset&#x27;s JSON tools copied into the project. The AWSiOsSDK also uses this json parser. Boum.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Gradle Build Variants for your android project</title>
		<published>2013-10-05T22:43:00+00:00</published>
		<updated>2013-10-05T22:43:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2013-10-06-gradle-build-variants-for-your-android-project-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2013-10-06-gradle-build-variants-for-your-android-project-html/</id>
		<content type="html">&lt;p&gt;When developing an app, you usually have many slightly different versions of this app. The most common example is probably the backend you want to use: &lt;em&gt;production&lt;&#x2F;em&gt; or &lt;em&gt;staging&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You usually define the base URLs with the other constants of the app. Switching from one environment to the other is done by (un)commenting the right lines:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;public static String BASE_URL = &amp;quot;http:&#x2F;&#x2F;staging.tamere.be&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F;public static String BASE_URL = &amp;quot;http:&#x2F;&#x2F;production.tamere.be&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The process is manual, boring and error prone but hey, changing one line is not that bad, is it?&lt;&#x2F;p&gt;
&lt;p&gt;Then you add more and more features that depends on the environment. You maybe want a different icon and then different input validation rules and then ...&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s where your build tool can help. Let&#x27;s see how we can automate the process of generating different APKs for different environment with Gradle.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;build-variants&quot;&gt;Build variants&lt;&#x2F;h2&gt;
&lt;p&gt;Gradle has the concepts of &lt;em&gt;Build Types&lt;&#x2F;em&gt; and &lt;em&gt;Build Flavors&lt;&#x2F;em&gt;. When combining the two, you get a &lt;em&gt;Build Variant&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There two default build types: &lt;em&gt;release&lt;&#x2F;em&gt; and &lt;em&gt;debug&lt;&#x2F;em&gt;. We won&#x27;t change them in our example but we will create two new flavors: &lt;em&gt;production&lt;&#x2F;em&gt; and &lt;em&gt;staging&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, we&#x27;ll have four different variants:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ProductionDebug&lt;&#x2F;li&gt;
&lt;li&gt;ProductionRelease&lt;&#x2F;li&gt;
&lt;li&gt;StagingDebug&lt;&#x2F;li&gt;
&lt;li&gt;StagingRelease&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;sample-project&quot;&gt;Sample project&lt;&#x2F;h2&gt;
&lt;p&gt;The project is pretty simple but shows how you can define for each build variant:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;an app name&lt;&#x2F;li&gt;
&lt;li&gt;an icon&lt;&#x2F;li&gt;
&lt;li&gt;constants (in our case a &lt;code&gt;BASE_URL&lt;&#x2F;code&gt; variable)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can download the project on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fstephany&#x2F;gradle-build-variant-example&quot;&gt;Github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here are two screenshots of the generated apps. Nothing really fancy:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;flavors-prod.png&quot; alt=&quot;Android App drawer showing the two differents flavors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;flavors-staging.png&quot; alt=&quot;Android App drawer showing the two differents flavors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;build-gradle-file&quot;&gt;build.gradle file&lt;&#x2F;h2&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;buildscript {
&lt;&#x2F;span&gt;&lt;span&gt;    repositories {
&lt;&#x2F;span&gt;&lt;span&gt;        mavenCentral()
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    dependencies {
&lt;&#x2F;span&gt;&lt;span&gt;        classpath &amp;#39;com.android.tools.build:gradle:0.5.+&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;apply plugin: &amp;#39;android&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;repositories {
&lt;&#x2F;span&gt;&lt;span&gt;    mavenCentral()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;android {
&lt;&#x2F;span&gt;&lt;span&gt;    compileSdkVersion 18
&lt;&#x2F;span&gt;&lt;span&gt;    buildToolsVersion &amp;quot;18.0.1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    defaultConfig {
&lt;&#x2F;span&gt;&lt;span&gt;        minSdkVersion 15
&lt;&#x2F;span&gt;&lt;span&gt;        targetSdkVersion 18
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    productFlavors {
&lt;&#x2F;span&gt;&lt;span&gt;        production {
&lt;&#x2F;span&gt;&lt;span&gt;            packageName &amp;quot;be.tamere.gradlebuildtypesexample&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        staging {
&lt;&#x2F;span&gt;&lt;span&gt;            packageName &amp;quot;be.tamere.gradlebuildtypesexample.staging&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;dependencies {
&lt;&#x2F;span&gt;&lt;span&gt;	compile &amp;#39;com.android.support:appcompat-v7:18.0.0&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The definition of the flavors is super simple, all the magic will happen in their folders.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;file-structure&quot;&gt;File structure&lt;&#x2F;h2&gt;
&lt;p&gt;In the &lt;code&gt;src&lt;&#x2F;code&gt; folder, we&#x27;ve created two directories whose names must match the flavors. We will define all the flavor-specific values. Only specific values are necessary.&lt;&#x2F;p&gt;
&lt;p&gt;The staging version defines new icons while both flavors defines a &lt;code&gt;Constants.java&lt;&#x2F;code&gt;. The app name is defined in the &lt;code&gt;string.xml&lt;&#x2F;code&gt; files.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;├── main
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── AndroidManifest.xml
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── ic_launcher-web.png
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── java
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── be
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── tamere
&lt;&#x2F;span&gt;&lt;span&gt;│   │           └── gradlebuildtypesexample
&lt;&#x2F;span&gt;&lt;span&gt;│   │               └── MainActivity.java
&lt;&#x2F;span&gt;&lt;span&gt;│   └── res
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── drawable-hdpi
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── drawable-mdpi
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── drawable-xhdpi
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── drawable-xxhdpi
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── layout
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── activity_main.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── menu
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── main.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── values
&lt;&#x2F;span&gt;&lt;span&gt;│       │   ├── dimens.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       │   ├── strings.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── styles.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── values-v11
&lt;&#x2F;span&gt;&lt;span&gt;│       │   └── styles.xml
&lt;&#x2F;span&gt;&lt;span&gt;│       └── values-v14
&lt;&#x2F;span&gt;&lt;span&gt;│           └── styles.xml
&lt;&#x2F;span&gt;&lt;span&gt;├── production
&lt;&#x2F;span&gt;&lt;span&gt;│   └── java
&lt;&#x2F;span&gt;&lt;span&gt;│       └── be
&lt;&#x2F;span&gt;&lt;span&gt;│           └── tamere
&lt;&#x2F;span&gt;&lt;span&gt;│               └── gradlebuildtypesexample
&lt;&#x2F;span&gt;&lt;span&gt;│                   └── Constants.java
&lt;&#x2F;span&gt;&lt;span&gt;└── staging
&lt;&#x2F;span&gt;&lt;span&gt;    ├── java
&lt;&#x2F;span&gt;&lt;span&gt;    │   └── be
&lt;&#x2F;span&gt;&lt;span&gt;    │       └── tamere
&lt;&#x2F;span&gt;&lt;span&gt;    │           └── gradlebuildtypesexample
&lt;&#x2F;span&gt;&lt;span&gt;    │               └── Constants.java
&lt;&#x2F;span&gt;&lt;span&gt;    └── res
&lt;&#x2F;span&gt;&lt;span&gt;        ├── drawable-hdpi
&lt;&#x2F;span&gt;&lt;span&gt;        │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;        ├── drawable-mdpi
&lt;&#x2F;span&gt;&lt;span&gt;        │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;        ├── drawable-xhdpi
&lt;&#x2F;span&gt;&lt;span&gt;        │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;        ├── drawable-xxhdpi
&lt;&#x2F;span&gt;&lt;span&gt;        │   └── ic_launcher.png
&lt;&#x2F;span&gt;&lt;span&gt;        └── values
&lt;&#x2F;span&gt;&lt;span&gt;            └── string.xml
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;android-studio&quot;&gt;Android Studio&lt;&#x2F;h2&gt;
&lt;p&gt;You can switch between the two flavors in the &lt;code&gt;Build variants&lt;&#x2F;code&gt; tab of the IDE. Android Studio has some trouble identifying the resources for a non-active flavors.&lt;&#x2F;p&gt;
&lt;p&gt;We are using the &lt;code&gt;production&lt;&#x2F;code&gt; flavor, Studio does not understand that the &lt;code&gt;staging&lt;&#x2F;code&gt; folder contains source code. Don&#x27;t worry, it&#x27;s normal, it will catch up when you switch to the staging variant.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;build-variants.png&quot; alt=&quot;Android Studio IDE showing different build variants&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Launch the app with the different flavors to see the result.&lt;&#x2F;p&gt;
&lt;p&gt;The app drawer shows the two icons:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;app-drawer.png&quot; alt=&quot;Android App drawer showing the two differents flavors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;tools.android.com&#x2F;tech-docs&#x2F;new-build-system&#x2F;user-guide#TOC-Product-flavors&quot;&gt;http:&#x2F;&#x2F;tools.android.com&#x2F;tech-docs&#x2F;new-build-system&#x2F;user-guide#TOC-Product-flavors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Xav&#x27;s answer on this &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;16737006&#x2F;using-build-flavors-structuring-source-folders-and-build-gradle-correctly&quot;&gt;Stack overflow topic&lt;&#x2F;a&gt; is particularly helpful.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>UILocalNotification alertBody</title>
		<published>2013-06-06T12:44:00+00:00</published>
		<updated>2013-06-06T12:44:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2013-06-06-uilocalnotification-alertbody-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2013-06-06-uilocalnotification-alertbody-html/</id>
		<content type="html">&lt;p&gt;Once again, this post is more a reminder to &lt;code&gt;self&lt;&#x2F;code&gt; than a real blog post but I&#x27;ve been
bitten by that one.&lt;&#x2F;p&gt;
&lt;p&gt;Always set the &lt;code&gt;alertBody&lt;&#x2F;code&gt; of a &lt;code&gt;UILocalNotification&lt;&#x2F;code&gt;. If you don&#x27;t, nothing will appear when the application is on the background. The &lt;a href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;ios&#x2F;#documentation&#x2F;iPhone&#x2F;Reference&#x2F;UILocalNotification_Class&#x2F;Reference&#x2F;Reference.html&quot;&gt;documentation&lt;&#x2F;a&gt; mentions it but it&#x27;s pretty easy to miss the remark:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Assign a string or, preferably, a localized-string key (using NSLocalizedString) as the value of the message. If the value of this property is non-nil, an alert is displayed. The default value is nil (no alert).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Creating a local notification without any content is probably not common but it can happen while developing with the &lt;em&gt;I will add text later&lt;&#x2F;em&gt; mindset.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Scroll UITableView to currently selected UITextField</title>
		<published>2013-05-20T23:30:00+00:00</published>
		<updated>2013-05-20T23:30:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2013-05-21-scroll-uitableview-to-currently-selected-uitextfield-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2013-05-21-scroll-uitableview-to-currently-selected-uitextfield-html/</id>
		<content type="html">&lt;h2 id=&quot;situation&quot;&gt;Situation&lt;&#x2F;h2&gt;
&lt;p&gt;I have a &lt;code&gt;UITableView&lt;&#x2F;code&gt;. Each cell of the table view has a &lt;code&gt;UITextField&lt;&#x2F;code&gt; in its &lt;code&gt;contentView&lt;&#x2F;code&gt;. The table view is actually a giant form.&lt;&#x2F;p&gt;
&lt;p&gt;In iOS when a tableView has cells containing textfield, it is supposed to scroll when a textfield becomes the first responder so focused textfield is visible when the user edits its content.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn&#x27;t the case for me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;Do not forget the &lt;code&gt;[textField resignFirstResponder]&lt;&#x2F;code&gt; when passing the &lt;code&gt;isFirstResponder&lt;&#x2F;code&gt; to the next textfield. Otherwise the tableView won&#x27;t scroll to the new first responder when editing.&lt;&#x2F;p&gt;
&lt;p&gt;{% highlight objective-c %}&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;(BOOL)textFieldShouldReturn:(UITextField &lt;em&gt;)textField {
NSInteger nextTag = textField.tag + 1;
UIView&lt;&#x2F;em&gt; nextResponder = [self.view viewWithTag:nextTag];
[textField resignFirstResponder];&lt;&#x2F;p&gt;
&lt;p&gt;if (nextResponder) {
[nextResponder becomeFirstResponder];
}
return YES;
}&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;{% endhighlight %}&lt;&#x2F;p&gt;
&lt;p&gt;Et voilà, the tableView will scroll as you expect.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo Sprint in Lille</title>
		<published>2012-11-04T12:30:00+00:00</published>
		<updated>2012-11-04T12:30:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-11-04-pharo-sprint-in-lille-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-11-04-pharo-sprint-in-lille-html/</id>
		<content type="html">&lt;p&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;rmod.lille.inria.fr&#x2F;&quot;&gt;RMoD&lt;&#x2F;a&gt; team held a sprint in their new office in &lt;a href=&quot;http:&#x2F;&#x2F;www.inria.fr&#x2F;en&#x2F;centre&#x2F;lille&quot;&gt;Inria Lille&lt;&#x2F;a&gt; last Friday. It was the occasion to meet in real life and to smash some bugs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;camillobruni&quot;&gt;Camillo&lt;&#x2F;a&gt; showed us how to use the bug tracker and how to submit a patch for integration. Overall the process is much easier than I expected.&lt;&#x2F;p&gt;
&lt;p&gt;I paired with Mariano for a couple of hours. We started something too big for the time we had so we warmed up on &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=6902&quot;&gt;an annoying bug&lt;&#x2F;a&gt; we found while fixing what we initially planned to do. We then tried to clean OSProcess&lt;a href=&quot;https:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=6855&quot;&gt; to load it in Pharo 2.0&lt;&#x2F;a&gt;. Once again, we probably picked something too big and I had to leave early so we didn&#x27;t finish but we made some progress (I hope ;))&lt;&#x2F;p&gt;
&lt;p&gt;&lt;div class=&#x27;p_embed p_image_embed&#x27;&gt;
&lt;img src=&#x27;&#x2F;images&#x2F;2012&#x2F;11&#x2F;45559858-DSC_0030.jpeg&#x27;&gt;
&lt;img src=&#x27;&#x2F;images&#x2F;2012&#x2F;11&#x2F;45559862-DSC_0036.jpeg&#x27;&gt;
&lt;img src=&#x27;&#x2F;images&#x2F;2012&#x2F;11&#x2F;45559863-IMG_1285.jpeg&#x27;&gt;
&lt;img src=&#x27;&#x2F;images&#x2F;2012&#x2F;11&#x2F;45559865-IMG_1286.jpeg&#x27;&gt;
&lt;&#x2F;div&gt;
(pictures by &lt;a href=&quot;http:&#x2F;&#x2F;marcusdenker.de&#x2F;&quot;&gt;Marcus Denker&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;In total, 18 bugs were solved (only two of them are not integrated yet), 8 others were fixed but need a second review and around 10 were closed for other reasons. All of this in a happy english&#x2F;french&#x2F;spanish speaking atmosphere.&lt;&#x2F;p&gt;
&lt;p&gt;I had never paired with someone in Smalltalk before. This kind of experience reminds me why I like programming. Thanks guys!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Migrating from MS Works to LibreOffice - batch processing</title>
		<published>2012-11-03T03:48:00+00:00</published>
		<updated>2012-11-03T03:48:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-11-03-migrating-from-ms-works-to-libreoffice-batch-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-11-03-migrating-from-ms-works-to-libreoffice-batch-html/</id>
		<content type="html">&lt;p&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Forensic_Medicine&quot;&gt;forensic doctor&lt;&#x2F;a&gt; came to me with a very specific problem; he was using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Microsoft_Works&quot;&gt;Microsoft Works&lt;&#x2F;a&gt; for years. He upgraded version after version without too much hassle but when Microsoft discontinued it, this doctor was worried about the long-term preservation of his data (all documents must be kept available for 30 years).&lt;&#x2F;p&gt;
&lt;p&gt;He grew up tired of Windows and to make things worse, he bought an iPhone last year. It was then decided that his next laptop would be a Mac.&lt;&#x2F;p&gt;
&lt;p&gt;Executing Works on a Mac is not an option in the long term but is tolerate during the migration, &lt;a href=&quot;http:&#x2F;&#x2F;www.parallels.com&#x2F;products&#x2F;desktop&#x2F;&quot;&gt;Parallels Desktop&lt;&#x2F;a&gt; has a great Coherence mode where Windows application behave like Mac ones.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Kill all the compiling!</title>
		<published>2012-09-28T12:44:00+00:00</published>
		<updated>2012-09-28T12:44:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-09-28-kill-all-the-compiling-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-09-28-kill-all-the-compiling-html/</id>
		<content type="html">&lt;p&gt;Two cool projects, one in Ruby&#x2F;Javascript, the other in Pharo Smalltalk. They both try to get rid of unnecessary compilation of source code.&lt;&#x2F;p&gt;
&lt;h2&gt;TurboLinks&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rails&#x2F;turbolinks&quot;&gt;TurboLinks&lt;&#x2F;a&gt; speeds up Rails app. Basically, when you click on a link of your application,  `body` and `title` are replaced. The browser does not load a whole new page. This avoids the recompilation of all the javascript and CSS by the browser. TurboLinks takes care of the history by using &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;DOM&#x2F;Manipulating_the_browser_history&quot;&gt;pushState&lt;&#x2F;a&gt;. It falls back to the regular behaviour if the browser does not support `pushState`.&lt;&#x2F;p&gt;
&lt;p&gt;The speedup is quite visible, especially if you have a lot of Javascript and are on a mobile browser.&lt;&#x2F;p&gt;
&lt;h2&gt;Tanker&lt;&#x2F;h2&gt;
&lt;p&gt;Managing packages in Pharo&#x2F;Squeak is quite a pain. Metacello helps but loading a project and all its dependencies takes a loooooong time. Try to load &lt;a href=&quot;http:&#x2F;&#x2F;www.seaside.st&#x2F;&quot;&gt;Seaside&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Magritte-Pier-and-Related-Tools-f115649.html&quot;&gt;Magritte&lt;&#x2F;a&gt;,  and &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;cloudfork&#x2F;&quot;&gt;CloudFork&lt;&#x2F;a&gt;, you&amp;rsquo;ll understand what I mean.&lt;&#x2F;p&gt;
&lt;p&gt;The reason is simple: a Monticello package contains the plain sources. When loading it, Pharo has to compile all the sources.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;marianopeck.wordpress.com&#x2F;2012&#x2F;09&#x2F;28&#x2F;new-tanker-current-status&#x2F;&quot;&gt;Tanker&lt;&#x2F;a&gt; uses the &lt;a href=&quot;http:&#x2F;&#x2F;rmod.lille.inria.fr&#x2F;web&#x2F;pier&#x2F;software&#x2F;Fuel&quot;&gt;Fuel serialiser&lt;&#x2F;a&gt; to load your code. It serialises the compiled methods and can restore them in another image without the need for recompiling.&lt;&#x2F;p&gt;
&lt;p&gt;Loading seaside now takes around 20 seconds (it could take ~10-15 minutes before).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;edit:&lt;&#x2F;em&gt; &lt;a href=&quot;http:&#x2F;&#x2F;marianopeck.wordpress.com&#x2F;&quot;&gt;Mariano&lt;&#x2F;a&gt;&amp;rsquo;s comment clarifies the loading speed of Tanker versus Monticello loading. I went a bit too fast to my conclusion ;)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;http:&#x2F;&#x2F;imgs.xkcd.com&#x2F;comics&#x2F;compiling.png&quot; alt=&quot;xkcd compiling&quot; &#x2F;&gt;
&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Seaside wrapper for Filepicker.io</title>
		<published>2012-09-26T18:17:00+00:00</published>
		<updated>2012-09-26T18:17:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-09-26-seaside-wrapper-for-filepickerio-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-09-26-seaside-wrapper-for-filepickerio-html/</id>
		<content type="html">&lt;p&gt;To me, uploading has always been the messier part in web application. Some will argue that the fun starts when you want to do ajax uploading.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;filepicker.io&#x2F;&quot;&gt;Filepicker.io&lt;&#x2F;a&gt; solves the problem quite elegantly. Mega bonus point, they integrate nicely with Dropbox, Gmail, Google drive, Facebook and others. So your user can pick a file on her hard drive, dropbox or even take a picture with the webcam.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;developers.filepicker.io&#x2F;docs&#x2F;web&#x2F;&quot;&gt;integration&lt;&#x2F;a&gt; is pretty straightforward but to make things even easier I&amp;rsquo;ve started a small wrapper for Seaside. You can find it on &lt;a href=&quot;http:&#x2F;&#x2F;ss3.gemstone.com&#x2F;ss&#x2F;Filepickerio.html&quot;&gt;Squeaksource 3&lt;&#x2F;a&gt;. Right now, it only performs the basic but I&amp;rsquo;ll add features when I need them.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;html form with: [
&lt;&#x2F;span&gt;&lt;span&gt;     html fileInput
&lt;&#x2F;span&gt;&lt;span&gt;          on: #uploadedFileUrl of: self;
&lt;&#x2F;span&gt;&lt;span&gt;          apiKey: &amp;#39;yourApiKey&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;          beDragNDrop.
&lt;&#x2F;span&gt;&lt;span&gt;     html break.
&lt;&#x2F;span&gt;&lt;span&gt;     html submitButton with: &amp;#39;Send the form.&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;].
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the user selects a file and sends the form, the instance variable `uploadedFileUrl` will contain the url of the uploaded file. You can then grab it and do whatever you want with the file.&lt;&#x2F;p&gt;
&lt;p&gt;You can grab the `Filepickerio-Test` package in the repo, it contains a sample application showing how to use it.&lt;&#x2F;p&gt;
&lt;p&gt;I&amp;rsquo;ve only tested on Pharo 1.4 Summer edition and Seaside 3.0.7. The code is quite simple and should work everywhere though…&lt;&#x2F;p&gt;
&lt;p&gt;Oh, the repo is global read&#x2F;write and the code is MIT ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Deploying Pharo Application</title>
		<published>2012-07-04T13:59:10+00:00</published>
		<updated>2012-07-04T13:59:10+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-07-04-deploying-pharo-application-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-07-04-deploying-pharo-application-html/</id>
		<content type="html">&lt;p&gt;People sometimes asks me how to deploy Smalltalk applications. I&amp;rsquo;ve only worked with Squeak and Pharo with server side application so I only covers those two dialects in that context.&lt;&#x2F;p&gt;
&lt;p&gt;It all start easy. Basically, you write a script that you can use with a process monitoring daemon (I use &lt;a href=&quot;http:&#x2F;&#x2F;rfw.posterous.com&#x2F;monit-101-an-developers-guide-to-system-monit&quot;&gt;monit&lt;&#x2F;a&gt; but any will do the trick). This daemon will start&#x2F;restart&#x2F;stop your application with your script. So far, I never had any problems with this system.&lt;&#x2F;p&gt;
&lt;p&gt;Now how does your startup script should look like? Here is an overview of the different possibilities. Please comment if you use an other strategy.&lt;&#x2F;p&gt;
&lt;h2&gt;Create an image locally and upload it&lt;&#x2F;h2&gt;
&lt;p&gt;That&amp;rsquo;s the most basic scenario. You create your image locally, load everything you need and then upload it to your server with S&#x2F;FTP. Slow and painful, you want to avoid this process.&lt;&#x2F;p&gt;
&lt;h2&gt;Load everything all the time&lt;&#x2F;h2&gt;
&lt;p&gt;Your script takes a fresh image, load your Metacello configuration and hopla, it&amp;rsquo;s ready to go. You never save the image. It is used as a runtime and there&amp;rsquo;s no need to save it. I love this approach for its simplicity. It is also pretty clean as you never rot your image and everything is wiped out when you restart.&lt;&#x2F;p&gt;
&lt;p&gt;Acutally it looks like a regular web application in, say, Ruby. Ruby loads your code and the dependent gems and run your code.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately it has a huge drawback. Metacello will look at all your dependencies and load the versions you defined. You need to rely on other people configurations and hope that their repo are still reachable. Have you ever encoutered a broken Metacello configuration? How many time &lt;a href=&quot;http:&#x2F;&#x2F;squeaksource.com&quot;&gt;squeaksource&lt;&#x2F;a&gt; has been down lately? The recent outage with Lukas Renggli repository (which contained many open source projects) also shows the limitation of this model.&lt;&#x2F;p&gt;
&lt;p&gt;Another issue is the time it takes to load packages with Monticello. Most of my projects depends on Seaside, Magritte, Cloudfork and others. Loading all those can take up to 20 minutes.  It means that you need to wait every time your application restarts. Annoying.&lt;&#x2F;p&gt;
&lt;p&gt;There&amp;rsquo;s a GSOC project going on that will solve this problem by providing binary packages (so you don&amp;rsquo;t need to recompile everything you load). It&amp;rsquo;s not there yet and you need a binary version of all the project you depend on.&lt;&#x2F;p&gt;
&lt;h2&gt;Prepare a base image with CI server&lt;&#x2F;h2&gt;
&lt;p&gt;For this one, you load your project and its dependencies once in an image. You save it. Then you tell your process monitoring daemon to just launch it. Once it started, you never save it. If it crashes, you simply restart the prepared image.&lt;&#x2F;p&gt;
&lt;p&gt;With this approach, you need to generate the base image. You can do it manually but a continuous integration server can help a lot. You can create a hook that regenerate the base image when you update your Metacello configuration for example.&lt;&#x2F;p&gt;
&lt;p&gt;This scenario removes the problem of loading time. When your application crashes, it can restart instantly, you don&amp;rsquo;t need to reload everything. But you need a CI server to automate the construction of the image.&lt;&#x2F;p&gt;
&lt;h2&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The first approach is clearly not optimal. It works for &lt;em&gt;very&lt;&#x2F;em&gt; small project but does not scale at all. Ideally, your deployment process should be as smooth as possible. A &lt;a href=&quot;http:&#x2F;&#x2F;heroku.com&quot;&gt;Heroku&lt;&#x2F;a&gt; like deployment would be super cool to have but so far Smalltalkers all have their own scripts, there are no standardized solutions.&lt;&#x2F;p&gt;
&lt;p&gt;Note that those strategies show their limitation only at the first launch or when they restart. In many situations, you can update your code when it&amp;rsquo;s running, without restarting the image.&lt;&#x2F;p&gt;
&lt;p&gt;Smalltalker, what is your deployment process?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Misc stuff about Voyage and MongoDB</title>
		<published>2012-05-28T17:01:00+00:00</published>
		<updated>2012-05-28T17:01:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-28-misc-stuff-about-voyage-and-mongodb-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-28-misc-stuff-about-voyage-and-mongodb-html/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;smallworks.com.ar&#x2F;&quot;&gt;Esteban&lt;&#x2F;a&gt; replied to my &lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2012-05-24-mongodb-with-voyage-in-pharo-html&#x2F;&quot;&gt;first post&lt;&#x2F;a&gt;&lt;&#x2F;a&gt; about &lt;a href=&quot;smalltalkhub.com&#x2F;#!&#x2F;~estebanlm&#x2F;Voyage&#x2F;&quot;&gt;Voyage&lt;&#x2F;a&gt;. Unfortunately, my blog provider messed up when formatting the comment. Here’s a summary of his remarks:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;magritte&quot;&gt;Magritte&lt;&#x2F;h2&gt;
&lt;p&gt;Magritte is not necessary for the basic scenarios. Voyage is smart enough to infer the types of your instance variables and can serialize them. You don’t need to describe everything like you would do when building an UI with Magritte.&lt;&#x2F;p&gt;
&lt;p&gt;The Magritte descriptions are only needed when you want to override the defaults of want to have a one-to-many relationships.&lt;&#x2F;p&gt;
&lt;p&gt;In the future, it will be able to infer the to-many relations automatically but at the moment you still have to tell voyage how to deal with them.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;^VOMongoToManyDescription new
&lt;&#x2F;span&gt;&lt;span&gt;    attributeName: &amp;#39;myInstVar&amp;#39;; &amp;quot;Acts on this inst var&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    kindCollection: Set; &amp;quot;Set instead an OrderedCollection&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    beLazy; &amp;quot;I want that references to be retrieved lazily&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    yourself.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Browse &lt;code&gt;VOMongoRelationDescription&lt;&#x2F;code&gt; and its subclasses to see what is possible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;embedded-documents&quot;&gt;Embedded documents&lt;&#x2F;h2&gt;
&lt;p&gt;As we&#x27;ve seen &lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2012-05-24-embedded-document-with-voyage-in-mongodb-html&#x2F;&quot;&gt;previously&lt;&#x2F;a&gt;, it is pretty easy to map a relation. In our example, we declared both &lt;code&gt;MQSpaceship&lt;&#x2F;code&gt; and &lt;code&gt;MQPilot&lt;&#x2F;code&gt; as persistent by implementing &lt;code&gt;isPersistent&lt;&#x2F;code&gt; on the class side.&lt;&#x2F;p&gt;
&lt;p&gt;This &lt;code&gt;isPersistent&lt;&#x2F;code&gt; method has an unfortunate name. It actually means that a collection with the name of the class will be created in the database. If we hadn’t declared &lt;code&gt;MQPilot&lt;&#x2F;code&gt; persistent, it would have been completely embedded in the spaceship.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ignore-instance-variable&quot;&gt;Ignore instance variable&lt;&#x2F;h2&gt;
&lt;p&gt;Sometimes you do not want to serialize &lt;em&gt;all&lt;&#x2F;em&gt; your instance variables. In such cases, add a &lt;code&gt;VOMongoTransientDescription&lt;&#x2F;code&gt; like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;mongoTransientDescription
&lt;&#x2F;span&gt;&lt;span&gt;  ^VOMongoTransientDescription new
&lt;&#x2F;span&gt;&lt;span&gt;    attributeName: ‘puppies’;
&lt;&#x2F;span&gt;&lt;span&gt;    yourself.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, the &lt;code&gt;puppies&lt;&#x2F;code&gt; instance variable will be ignored by the serializer and won’t be stored in Mongo.&lt;&#x2F;p&gt;
&lt;p&gt;That’s all for today. Once again, huge thanks to Esteban for this super nice library!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Embedded Document with Voyage in MongoDB</title>
		<published>2012-05-24T19:15:00+00:00</published>
		<updated>2012-05-24T19:15:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-24-embedded-document-with-voyage-in-mongodb-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-24-embedded-document-with-voyage-in-mongodb-html/</id>
		<content type="html">&lt;p&gt;In my &lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2012-05-24-mongodb-with-voyage-in-pharo-html&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;. I was wondering how Voyage would handle embedded documents. The answer is pretty simple. Let’s see with an example ( &lt;strong&gt;MQ&lt;&#x2F;strong&gt; stands for for &lt;em&gt;Mars Quest&lt;&#x2F;em&gt;):&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Object subclass: #MQSpaceship
&lt;&#x2F;span&gt;&lt;span&gt;   instanceVariableNames: &amp;#39;pilot name&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   classVariableNames: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   poolDictionaries: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   category: &amp;#39;MarsQuest&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Object subclass: #MQPilot
&lt;&#x2F;span&gt;&lt;span&gt;   instanceVariableNames: &amp;#39;name&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   classVariableNames: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   poolDictionaries: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;   category: &amp;#39;MarsQuest&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;MQSpaceship class&amp;amp;gt;&amp;amp;gt;isPersistent
&lt;&#x2F;span&gt;&lt;span&gt;   ^true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;MQPilot class&amp;amp;gt;&amp;amp;gt;isPersistent
&lt;&#x2F;span&gt;&lt;span&gt;   ^true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Generate the accessors for the instance variables (yeah, &lt;code&gt;name&lt;&#x2F;code&gt; is super annoying). And execute the following:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;(MQSpaceship new
&lt;&#x2F;span&gt;&lt;span&gt;    name: &amp;#39;Batmobile&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;    pilot: (MQPilot new name: &amp;#39;Batman&amp;#39;)) save.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Voyage will generate two collection in your database: &lt;code&gt;spaceship&lt;&#x2F;code&gt; and &lt;code&gt;pilot&lt;&#x2F;code&gt;. The spaceship record we’ve just created is:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;_id&amp;quot;: ObjectId(&amp;quot;f65bd8790000000000000000&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;#instanceOf&amp;quot;: &amp;quot;MQSpaceship&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;name&amp;quot;: &amp;quot;Batmobile&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;pilot&amp;quot;: {
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;#collection&amp;quot;: &amp;quot;pilot&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;#instanceOf&amp;quot;: &amp;quot;MQPilot&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;__id&amp;quot;: ObjectId(&amp;quot;85f61e070000000000000000&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;   }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the pilot record:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;_id&amp;quot;: ObjectId(&amp;quot;85f61e070000000000000000&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;#instanceOf&amp;quot;: &amp;quot;MQPilot&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;name&amp;quot;: &amp;quot;Batman&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So we didn’t completely embed the Pilot into the Spaceship document but have defined a relation. This is something you would or wouldn’t want depending of your data and what kind of query you need to perform on them (&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=PIWVFUtBV1Q&quot;&gt;this talk&lt;&#x2F;a&gt; explains modeling choices in MongoDB).&lt;&#x2F;p&gt;
&lt;p&gt;When you retrieve the Spaceship, the Pilot is also automatically fetched.&lt;&#x2F;p&gt;
&lt;p&gt;Once again, this post is pretty straightforward and more a loud thinking about &lt;a href=&quot;http:&#x2F;&#x2F;smalltalkhub.com&#x2F;#!&#x2F;~estebanlm&#x2F;Voyage&#x2F;&quot;&gt;Voyage&lt;&#x2F;a&gt; than a real structured tutorial&#x2F;article. Hopefully it will end up in something useful for someone.&lt;&#x2F;p&gt;
&lt;p&gt;If not, you can always enjoy the uber cool hair design in the videoclip of &lt;em&gt;Voyage, voyage&lt;&#x2F;em&gt; from Desireless:&lt;&#x2F;p&gt;
&lt;iframe src=&quot;http:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;6PDmZnG8KsM?wmode=transparent&quot;
        frameborder=&quot;0&quot;
        height=&quot;417&quot;
        width=&quot;628&quot;&gt;video&lt;&#x2F;iframe&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>MongoDB with Voyage  in Pharo</title>
		<published>2012-05-24T17:21:00+00:00</published>
		<updated>2012-05-24T17:21:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-24-mongodb-with-voyage-in-pharo-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-24-mongodb-with-voyage-in-pharo-html/</id>
		<content type="html">&lt;p&gt;Esteban published &lt;a href=&quot;http:&#x2F;&#x2F;smalltalkhub.com&#x2F;#!&#x2F;~estebanlm&#x2F;Voyage&#x2F;&quot;&gt;Voyage&lt;&#x2F;a&gt;, a library for persisting objects in Smalltalk. It uses &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;magritte-metamodel&#x2F;&quot;&gt;Magritte&lt;&#x2F;a&gt; to get descriptions from your domain model. At the moment, &lt;a href=&quot;http:&#x2F;&#x2F;www.mongodb.org&#x2F;&quot;&gt;MongoDB&lt;&#x2F;a&gt; and the image are the two possible backend for Voyage.&lt;&#x2F;p&gt;
&lt;p&gt;If you are not familiar with MongoDB and Document based databases, this &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=PIWVFUtBV1Q&quot;&gt;presentation&lt;&#x2F;a&gt; (~1h) by Jared Rosoff should help you to grasp the differences with the RDBMS world.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to play a bit with Pharo and MongoDB, there’s a &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;MongoTalk&quot;&gt;MongoTalk&lt;&#x2F;a&gt;, a simple smalltalk driver which works well but is quite low level. I wanted something that can be easily integrated with Magritte.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s some dabbling with it and Pharo 1.4 (version 14441). Nothing really fancy, we will just save an object.&lt;&#x2F;p&gt;
&lt;p&gt;The Metacello configuration will take care of installation:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Gofer it
&lt;&#x2F;span&gt;&lt;span&gt;  url: &amp;#39;http:&#x2F;&#x2F;smalltalkhub.com&#x2F;mc&#x2F;estebanlm&#x2F;Voyage&#x2F;main&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  package: &amp;#39;ConfigurationOfVoyage&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  load.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;ConfigurationOfVoyage project bleedingEdge load: &amp;#39;Mongo&amp;#39;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Update August 2012&lt;&#x2F;strong&gt;
Esteban created two different configuration &lt;code&gt;ConfigurationOfVoyageMongo&lt;&#x2F;code&gt; and &lt;code&gt;ConfigurationOfPierVoyage&lt;&#x2F;code&gt;. You should use the former for loading Voyage:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Gofer it
&lt;&#x2F;span&gt;&lt;span&gt;  url: &amp;#39;http:&#x2F;&#x2F;smalltalkhub.com&#x2F;mc&#x2F;estebanlm&#x2F;Voyage&#x2F;main&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  package: &amp;#39;ConfigurationOfVoyageMongo&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  load.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(ConfigurationOfVoyageMongo project version: &amp;#39;1.0&amp;#39;) load: &amp;#39;Mongo&amp;#39;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are going to assume you have a default MongoDB setup.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;repo := VOMongoRepository
&lt;&#x2F;span&gt;&lt;span&gt;  host: VOMongoRepository defaultHost
&lt;&#x2F;span&gt;&lt;span&gt;  database: &amp;#39;voyage-play&amp;#39;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And setup this repository as the default one:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;VORepository setRepository: repo.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Declare a new class. Don’t pay attention to my model, I’m designing the next social network that will bring humans to Mars.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Object subclass: #Brolinou
&lt;&#x2F;span&gt;&lt;span&gt;  instanceVariableNames: &amp;#39;title&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  classVariableNames: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  poolDictionaries: &amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  category: &amp;#39;Brol&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Brolinou&amp;gt;&amp;gt;title
&lt;&#x2F;span&gt;&lt;span&gt;^title
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Brolinou&amp;gt;&amp;gt;title: aString
&lt;&#x2F;span&gt;&lt;span&gt;title := aString
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Brolinou class&amp;gt;&amp;gt;isPersistent
&lt;&#x2F;span&gt;&lt;span&gt;^true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last one is important. Voyage is now aware that you can persist &lt;code&gt;Brolinou&lt;&#x2F;code&gt; objects.&lt;&#x2F;p&gt;
&lt;p&gt;The weird thing is that Voyage currently depends on Magritte 2. I don’t know if you’ve already migrated to Magritte 3 but it bothers me a bit to start a new project with Magritte 2. I’m by no means a Magritte expert, there a probably good reasons to stay with that version. It is maybe that time is scarce and that Esteban is working like crazy on many other projects ;)&lt;&#x2F;p&gt;
&lt;p&gt;Anyway we gonna add a description for our title field:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;titleDescription
&lt;&#x2F;span&gt;&lt;span&gt;  ^MAStringDescription new
&lt;&#x2F;span&gt;&lt;span&gt;     label: &amp;#39;titre&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;     accessor: #title;
&lt;&#x2F;span&gt;&lt;span&gt;     yourself.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Time to open a workspace and dabble with our model:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;brol := Brolinou new title: &amp;#39;Going to Mars!&amp;#39;.
&lt;&#x2F;span&gt;&lt;span&gt;brol isNew. &amp;quot;=&amp;gt; true&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;brol save.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tadadada! Open the Mongo shell or your favorite interface to it (I’m using &lt;a href=&quot;http:&#x2F;&#x2F;rockmongo.com&#x2F;&quot;&gt;RockMongo&lt;&#x2F;a&gt;). You should see a new collection. The weird thing is that the new collection is named &lt;code&gt;olinou&lt;&#x2F;code&gt; in the database &lt;code&gt;voyage-play&lt;&#x2F;code&gt;. I was expecting something like &lt;code&gt;brolinou&lt;&#x2F;code&gt;. Remember that we are running the bleeding edge version of Voyage so it’s not that important.&lt;&#x2F;p&gt;
&lt;p&gt;You should have an entry that looks like:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;_id&amp;quot;: ObjectId(&amp;quot;69b4a62c0000000000000000&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;#instanceOf&amp;quot;: &amp;quot;Brolinou&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;title&amp;quot;: &amp;quot;Going to Mars!&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see here that a field `#instanceOf&amp;quot; has been added to the record. It is probably used at materialization. You can now query your class to retrieve all the Brolinou instances:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Brolinou selectAll.
&lt;&#x2F;span&gt;&lt;span&gt;Brolinou selectMany: { #title -&amp;gt; &amp;#39;Going to Mars!&amp;#39;} asDictionary.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To see all the available methods, browse the &lt;code&gt;Voyage-Model-Core&lt;&#x2F;code&gt; protocol in the class &lt;code&gt;Class&lt;&#x2F;code&gt;. The &lt;code&gt;persistence&lt;&#x2F;code&gt; protocol of &lt;code&gt;VOMongoRepository&lt;&#x2F;code&gt; is quite interesting as well.&lt;&#x2F;p&gt;
&lt;p&gt;That’s all! Here are the topics I’d like to cover next:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Queries&lt;&#x2F;li&gt;
&lt;li&gt;Index&lt;&#x2F;li&gt;
&lt;li&gt;So far, Voyage will create a collection named after the class. With embedded objects you don’t always want that behavior. There’s probably a way to override that, i’m wondering how it is made.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;edit&quot;&gt;Edit&lt;&#x2F;h2&gt;
&lt;p&gt;The issue with the collection name is caused by the following code:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;VOMongoContainer class&amp;gt;&amp;gt;defaultCollectionName
&lt;&#x2F;span&gt;&lt;span&gt;  ^(self label allButFirst: 2) asLegalSelector
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This decision was probably made because of the lack of namespaces in Pharo. So people prefix their model class with two letters (e.g., &lt;strong&gt;WA&lt;&#x2F;strong&gt;Tag, &lt;strong&gt;FS&lt;&#x2F;strong&gt;Locator, &lt;strong&gt;Zn&lt;&#x2F;strong&gt;Entity). It makes sense now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;edit-two&quot;&gt;Edit two&lt;&#x2F;h2&gt;
&lt;p&gt;It seems that the Magritte description is useless in this case. Voyage will happily serialize the &lt;code&gt;title&lt;&#x2F;code&gt; instance variable automatically. See my &lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2012-05-24-embedded-document-with-voyage-in-mongodb-html&#x2F;&quot;&gt;next post&lt;&#x2F;a&gt; for more.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Vancouver Smalltalk Developer Group</title>
		<published>2012-05-23T16:13:00+00:00</published>
		<updated>2012-05-23T16:13:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-23-vancouver-smalltalk-developer-group-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-23-vancouver-smalltalk-developer-group-html/</id>
		<content type="html">&lt;p&gt;The first meeting of the &lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;Vancouver-Smalltalk-Developers-Group&#x2F;&quot;&gt;Vancouver Smalltalk Developer Group&lt;&#x2F;a&gt; was pretty good! Nine people showed up, which is quite nice considering the size of the Smalltalk community and the fact that it was the first event. Unfortunately I forgot to take pictures, probably a side effect of interesting discussions ;)&lt;&#x2F;p&gt;
&lt;p&gt;We got the meeting room of a Waves coffee shop in downtown Vancouver, the venue is allright but there is no projector and we were kicked out of the room at 8.30.&lt;&#x2F;p&gt;
&lt;p&gt;The next event is on its way. The date is not decided yet but it will happen between the 11th and 16th of June (tell us what&amp;rsquo;s better for you in &lt;a href=&quot;http:&#x2F;&#x2F;www.doodle.com&#x2F;bycw6xw9xtggt5ru&quot;&gt;the doodle&lt;&#x2F;a&gt;). If you are in the area, you&amp;rsquo;re more than welcome even if you&amp;rsquo;re not a smalltalker.&lt;&#x2F;p&gt;
&lt;p&gt;In the future, please subscribe to the &lt;a href=&quot;http:&#x2F;&#x2F;www.meetup.com&#x2F;Vancouver-Smalltalk-Developers-Group&#x2F;&quot;&gt;Meetup group&lt;&#x2F;a&gt;, the &lt;a href=&quot;http:&#x2F;&#x2F;lists.esug.org&#x2F;mailman&#x2F;listinfo&#x2F;esug-list_lists.esug.org&quot;&gt;ESUG&lt;&#x2F;a&gt; list or the &lt;a href=&quot;http:&#x2F;&#x2F;scona.us&#x2F;mailman&#x2F;listinfo&#x2F;scona-list&quot;&gt;SCONA&lt;&#x2F;a&gt; list to be in the loop ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Global package cache &amp;amp; stdin, stdout, stderr on Pharo</title>
		<published>2012-05-18T13:17:00+00:00</published>
		<updated>2012-05-18T13:17:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-18-global-package-cache-stdin-stdout-stderr-on-p-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-18-global-package-cache-stdin-stdout-stderr-on-p-html/</id>
		<content type="html">&lt;p&gt;When loading a package with Monticello, a copy is cached in the directory &amp;lsquo;package-cache&amp;rsquo; in your image folder. This is super useful when you need a package that you already have downloaded. Unfortunately, this cache is limited to the image directory. If you need that package in another image which is in another directory, you&amp;rsquo;ll have to &lt;em&gt;redownload&lt;&#x2F;em&gt; the package.&lt;&#x2F;p&gt;
&lt;p&gt;Here&amp;rsquo;s a little trick to have a global package cache:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;MCCacheRepository default directory:
&lt;&#x2F;span&gt;&lt;span&gt;  (FileDirectory on: &amp;#39;&#x2F;home&#x2F;fstephany&#x2F;package-cache&#x2F;&amp;#39;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, adapt the path to your configuration. Thanks Mariano for the tips (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Having-a-shared-package-cache-Re-MCDirectoryRepository-defaultDirectoryName-ignored-td3924814.html&quot;&gt;original discussion&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Another super useful things is the ability to send stuff to `sdtin`, `stdout` and `stderr`. I don&amp;rsquo;t know if it was present prior Pharo 1.3 but I&amp;rsquo;ve just discovered how to play with the standard streams:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;FileStream stdout nextPutAll: &amp;#39;Yopla&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Browse the class side of FileStream for more ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Limit hard dependencies in your code</title>
		<published>2012-05-17T13:31:00+00:00</published>
		<updated>2012-05-17T13:31:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-17-limit-hard-dependencies-in-your-code-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-17-limit-hard-dependencies-in-your-code-html/</id>
		<content type="html">&lt;p&gt;Igor Stasenko &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Moving-data-into-new-package-image-version-tp4628820p4630575.html&quot;&gt;summarizes what he does&lt;&#x2F;a&gt; to avoid coding with hard dependencies in his code:&lt;&#x2F;p&gt;
&lt;blockquote&gt;&lt;p&gt;Rule #1. never make more than 1 reference to any class external to your package in your code. an exception is kernel classes.&lt;&#x2F;p&gt;
&lt;p&gt;which means, that you are allowed to do `Set new` or `Array new`, in any place of your code but never `SomeFooClass new` more than once.&lt;&#x2F;p&gt;
&lt;p&gt;If your code having such dependency, localize it in single method:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;fooClass
&lt;&#x2F;span&gt;&lt;span&gt;  ^ FooClass
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and then use `self fooClass` everywhere..
Like that, if you will figure out one day, that sand moves under your feets, you&amp;rsquo;ll have to change only single method. :)&lt;&#x2F;p&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;I never felt the need of doing that when the refactoring browser can rename all that for you but it&amp;rsquo;s still make sense if you want cleaner code.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks Igor :)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Migrating to Pharo 1.4</title>
		<published>2012-05-01T22:45:00+00:00</published>
		<updated>2012-05-01T22:45:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2012-05-02-migrating-to-pharo-14-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2012-05-02-migrating-to-pharo-14-html/</id>
		<content type="html">&lt;p&gt;You&amp;rsquo;ve probably heard that Pharo 1.4 is out. This version contains many improvements (as software developers like to say) and some aspects have changed quite a lot.&lt;&#x2F;p&gt;
&lt;p&gt;One the Pharo team&amp;rsquo;s goal is to clean Squeak. Version 1.4 has made some critical steps toward this goal and more than 850 tickets have been closed. Impressive.&lt;&#x2F;p&gt;
&lt;p&gt;What is still lacking though is a detailed changelog of all the API changes. Sure, there&amp;rsquo;s a &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;wiki&#x2F;ActionsInPharoOneDotFour&quot;&gt;release note&lt;&#x2F;a&gt; but hey what does &lt;em&gt;Better headless support&lt;&#x2F;em&gt; mean?&lt;&#x2F;p&gt;
&lt;p&gt;I&amp;rsquo;ve switched some of my projects from 1.3 to 1.4. I haven&amp;rsquo;t tested everything in production yet but here are my first surprises:&lt;&#x2F;p&gt;
&lt;h2&gt;FS integration&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;fs.html&quot;&gt;FileSystem&lt;&#x2F;a&gt; (or FS) library has been integrated. FS is a replacement for the aging `FileDirectory`. Manipulating files is now much easier and the API is less chaotic than its predecessor. The `FileDirectory` is still there for compatibility reasons I guess but you shouldn&amp;rsquo;t use it anymore.&lt;&#x2F;p&gt;
&lt;p&gt;If you used the FileSystem library before, beware that the FS prefix has been changed to &amp;ldquo;File&amp;rdquo; (i.e., `FSLocator` becomes `FileLocator`). Update your code accordingly.&lt;&#x2F;p&gt;
&lt;p&gt;If your project has a MetacelloConfiguration that loads FS, you don&amp;rsquo;t need it anymore for 1.4&lt;&#x2F;p&gt;
&lt;h2&gt;Startup scripts&lt;&#x2F;h2&gt;
&lt;p&gt;That one was missing for quite a long time. Pharo will now look up in your home directory for startup file in the following order:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;#{image_directory}&#x2F;startup.st
&lt;&#x2F;span&gt;&lt;span&gt;~&#x2F;.config&#x2F;pharo&#x2F;#{version}&#x2F;startup.st
&lt;&#x2F;span&gt;&lt;span&gt;~&#x2F;.config&#x2F;pharo&#x2F;general&#x2F;pharo#{version}.st
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This has bitten me when deploying an a server. I used to launch my image with the following:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;exec $VM $VM_PARAMS $IMAGE $STARTUP_SCRIPT
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where `$STARTUP_SCRIPT` is the path to a `.st` file. That file was named `startup.st`. My startup script was executed twice without I realized it. It took me some time to realize what was going on ;)&lt;&#x2F;p&gt;
&lt;p&gt;Beware, it seems that this feature is not reliable (or not implemented?) on Windows.&lt;&#x2F;p&gt;
&lt;h2&gt;No default browser&lt;&#x2F;h2&gt;
&lt;p&gt;Pharo 1.3 used to be shipped with OmniBrowser (OB). This is not the case anymore and the default browser is now the basic one. No advanced features, no refactoring, plain boring.&lt;&#x2F;p&gt;
&lt;p&gt;The best choice is to load Nautilus, a browser developed by Benjamin Van Ryseghem. There is &lt;a href=&quot;https:&#x2F;&#x2F;ci.lille.inria.fr&#x2F;pharo&#x2F;view&#x2F;Nautilus%201.4&#x2F;job&#x2F;Nautilus&#x2F;&quot;&gt;a job on the CI build server&lt;&#x2F;a&gt; which contains the latest version of Pharo 1.4 and Nautilus.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, I had some troubles with it. When using the build from CI, loading seaside didn&amp;rsquo;t work. And when I load Seaside in a clean 1.4 image and then loading Nautilus, some strange problems occurs (like the font changes). I haven&amp;rsquo;t really investigated yet but that smells like bleeding edge piece of software.&lt;&#x2F;p&gt;
&lt;p&gt;The browser is pretty cool though and it is definitely a huge step from OB. My muscle memory is still trained for OB, which complicates the transition :p&lt;&#x2F;p&gt;
&lt;h2&gt;All in all&lt;&#x2F;h2&gt;
&lt;p&gt;This release is a good one, the Pharo team did an awesome job and I can&amp;rsquo;t wait to see what the 2.0 will look like. They apparently &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;About-the-new-release-process-td4574410.html&quot;&gt;changed their release process&lt;&#x2F;a&gt; for a time-based versioning (à la Ubuntu). Time will say if it&amp;rsquo;s a good choice&amp;hellip;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Send email from Pharo with Postmark</title>
		<published>2011-12-29T17:22:00+00:00</published>
		<updated>2011-12-29T17:22:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-29-send-email-from-pharo-with-postmark-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-29-send-email-from-pharo-with-postmark-html/</id>
		<content type="html">&lt;p&gt;I recently needed to send emails from a Pharo image. There is a SMTP client integrated in the standard libray but I wanted  to wrap the excellent &lt;a href=&quot;http:&#x2F;&#x2F;postmarkapp.com&#x2F;&quot;&gt;Postmark&lt;&#x2F;a&gt; REST &lt;a href=&quot;http:&#x2F;&#x2F;developer.postmarkapp.com&#x2F;developer-build.html&quot;&gt;API&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You can load it from &lt;a href=&quot;http:&#x2F;&#x2F;ss3.gemstone.com&#x2F;&quot;&gt;SqueakSource 3&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Gofer it
&lt;&#x2F;span&gt;&lt;span&gt;     url: &amp;#39;http:&#x2F;&#x2F;ss3.gemstone.com&#x2F;ss&#x2F;postmark&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;     package: &amp;#39;ConfigurationOfPostMark&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;     load.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(Smalltalk at: #ConfigurationOfPostMark) project stableVersion load.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And you can use it like:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;| email interface |
&lt;&#x2F;span&gt;&lt;span&gt;email := PMEmail new
&lt;&#x2F;span&gt;&lt;span&gt;  from: &amp;#39;francois@wapict.be&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  to: &amp;#39;francois@yopmail.com&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  subject: &amp;#39;Test Application&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  textBody: &amp;#39;Yeah baby&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  yourself.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;interface := PMInterface new.
&lt;&#x2F;span&gt;&lt;span&gt;interface apiKey: &amp;#39;blopblop&amp;#39;.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;interface send: email.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The implementation is really basic and does not handle attachments at the moment. I use it on a staging application that will probably be in production in January. I will see how it behaves under small load and improve it if needed.&lt;&#x2F;p&gt;
&lt;p&gt;edit: you can now attach files to your emails !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Windows Phone 7</title>
		<published>2011-12-28T12:54:00+00:00</published>
		<updated>2011-12-28T12:54:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-28-windows-phone-7-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-28-windows-phone-7-html/</id>
		<content type="html">&lt;p&gt;I&amp;rsquo;ve written this article in June 2011 and never published it. Now that Nokia has shipped their phones and the Mango (aka Windows Phone 7.5) is everywhere, it&amp;rsquo;s maybe time to click on the &lt;em&gt;publish&lt;&#x2F;em&gt; button ;)&lt;&#x2F;p&gt;
&lt;p&gt;When reading reviews of WP7.5, Microsoft has fixed almost all the issues I had with my LG Optimus 7 phone. Unfortunately, it broke during the (awesome) &lt;a href=&quot;http:&#x2F;&#x2F;dourfestival.be&#x2F;&quot;&gt;Dour festival&lt;&#x2F;a&gt;. The phone became crazy and kept rebooting. (In case you are wondering, fifteen minutes of cycling reboots keeps your phone hot). The shop where I bought it did not plan to get any Windows Phone soon so they gave me a Galaxy S2 (almost) for free.&lt;&#x2F;p&gt;
&lt;p&gt;While Android 2.3 is packed with wonderful features, it&amp;rsquo;s not as polished as the WP7 phone I owned but it usually works well. Android 4 is said to address this but I don&amp;rsquo;t think it will be as fresh and usable than Windows Phone. Anyway, here&amp;rsquo;s the short review I wrote back in June:&lt;&#x2F;p&gt;
&lt;p&gt;I was the first to be surprised when I came back home with a windows phone in my bag. Three months later, it&amp;rsquo;s time to report.&lt;&#x2F;p&gt;
&lt;p&gt;A bit of context: I&amp;rsquo;m a big fan of Apple products for seven years now (and I was a Linux user before). MacOS X is an impressive operating system: the geek inside me loves UNIX, the end user part of me likes the &amp;lsquo;everything works out of the box&amp;rsquo; side of the Mac experience.&lt;&#x2F;p&gt;
&lt;p&gt;Long story short, I love this Windows Phone 7.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Tiles are awesome. Simple, no gradient, no round corners, ni shiny effect, just the fact. Data-ink ratio is very high, Tuft would be happy.&lt;&#x2F;li&gt;
&lt;li&gt;Menus are kept to their minimum. There are not tons of options everywhere. Microsoft provided a very opiniated way of using the phone and they made the right choice almost every time.&lt;&#x2F;li&gt;
&lt;li&gt;All in all, this Metro UI is particularly well thought. Navigation follows a consistent pattern through the OS. Third party applications tend to adopt it.&lt;&#x2F;li&gt;
&lt;li&gt;Animations are plain right. Very subtle, never too long, they are visually pleasant and serve their purpose very well. They bring a sensation of fluidity and smoothness.&lt;&#x2F;li&gt;
&lt;li&gt;No custom ringtones. That sounds ridiculous but it clearly shows the direction taken by the creators of the OS.&lt;&#x2F;li&gt;
&lt;li&gt;Actually one of the only possible customisation is to change the dominant color. My favourite is Magenta. The color will be used almost everywhere in your phone. Elegant.&lt;&#x2F;li&gt;
&lt;li&gt;The Mac software is simple and easy to use. It synchronises your phone with iTunes&#x27; data. Don&amp;rsquo;t know if Apple appreciates but it works just fine&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;I have mixed feelings about the web browser though. Navigation is fast and fluid but javascript performance and CSS handling sucks at best. The navigation bar disappear when you are in landscape mode. That&amp;rsquo;s quite weird. Microsoft says it is based on a mix of IE 7 and 8. Fortunately, they will ship IE9 with the next release of Windows Phone.
The stuff that could have been added without too much boilerplate:&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;They screwed up with the first update of the OS. It brought copy-pasting but deployment was a nightmare for Microsoft.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Notification LED. My android phone had a small LED hiddden in the speaker. Even when you&amp;rsquo;re phone is in silent mode you can see in one eye glance if you&#x27;vre a text or missed a call. &lt;em&gt;very&lt;&#x2F;em&gt; useful&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;No threads in emails. Epic fail.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;No tethering. Annoying in the train.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;No multiple calendars when synced with Google Calendar.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;I cannot find a good Remember The Milk app. WinMilk is way to slow to be usable (yeah, I know, it is open source it is up to me to improve it instead of complaining)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This week, Microsoft unveiled a new version of WP7 called &amp;lsquo;Mango&amp;rsquo; or WP7.5. This update brings &lt;em&gt;a lot&lt;&#x2F;em&gt; of new features. Hopefully they won&amp;rsquo;t screw the whole Metro experience (fingers crossed).&lt;&#x2F;p&gt;
&lt;p&gt;All in all, forget Windows Mobile 6.x, Microsoft changed everything. The subtle rename from Windows Mobile to Windows Phone is not innocent.&lt;&#x2F;p&gt;
&lt;p&gt;I can&amp;rsquo;t believe I&amp;rsquo;ve just said something good about Microsoft software.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Legacy projects</title>
		<published>2011-12-19T18:51:00+00:00</published>
		<updated>2011-12-19T18:51:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-19-legacy-projects-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-19-legacy-projects-html/</id>
		<content type="html">&lt;p&gt;As a company or freelance developer you have probably encounter the dilemma of taking over somebody else code. On one side you are happy to get new work, on the other side dealing with legacy code can be frightening.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some questions you will need to ask when you continue and maintain a project:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What kind of client will you get when accepting the project?&lt;&#x2F;li&gt;
&lt;li&gt;How was the relation between the previous developer and the client?&lt;&#x2F;li&gt;
&lt;li&gt;Where is the project hosted? Do you have control over it?&lt;&#x2F;li&gt;
&lt;li&gt;What are the dependencies of the project? Ruby 1.8.6, Rails 1.2? RMagick? Will you have to migrate it to newer versions at some point? Does the client understand that you &lt;em&gt;need&lt;&#x2F;em&gt; to upgrade libraries and frameworks?&lt;&#x2F;li&gt;
&lt;li&gt;More generally, is the client aware that software needs maintenance?&lt;&#x2F;li&gt;
&lt;li&gt;Will you be the one responsible for old bugs that are discovered &lt;em&gt;after&lt;&#x2F;em&gt; you took over the project? Usually the client sees a bunch a stuff not working once you start to work on the project.&lt;&#x2F;li&gt;
&lt;li&gt;Have you considered a code review before accepting the project? Who did it? Someone external? The previous developer (hint: blink in red in your radar)?&lt;&#x2F;li&gt;
&lt;li&gt;Will you need to implement big new features? How the previous developer used to bill the client for them?&lt;&#x2F;li&gt;
&lt;li&gt;Is the client aware that you will probably be a bit slower than the previous developer when you start working on the project?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Many of these questions sounds stupid or simple good sense but a checklist is never too much when it comes to such a tricky decision.&lt;&#x2F;p&gt;
&lt;p&gt;Everybody likes to write &lt;em&gt;new&lt;&#x2F;em&gt; code. Maintaining code is usually less appealing.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;love&lt;&#x2F;em&gt; to dig in somebody else code,to refactor it, to understand what the previous developer had in mind when doing it. I like to remove the small imprecisions here and there and to curse when I see useless javascript files or two hundreds lines of commented code.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Smalltalk &amp;amp; native UI</title>
		<published>2011-12-11T12:26:00+00:00</published>
		<updated>2011-12-11T12:26:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-11-smalltalk-native-ui-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-11-smalltalk-native-ui-html/</id>
		<content type="html">&lt;p&gt;From time to time, someone on the Pharo mailing list asks how to build a desktop application.&lt;&#x2F;p&gt;
&lt;p&gt;A long time ago, Smalltalk was a great way to make desktop apps. drag &amp;amp; drop, rich visual interface, mouse pointer. Yeah, the mouse was quite a big thing.&lt;&#x2F;p&gt;
&lt;p&gt;Things have changed. People expect consistency from the software they use. Not only in the look but also in the feel. They want their applications to be tightly integrated with their operating systems. If you&amp;rsquo;re considering a niche application where people only care about the functional part of the system, that could work. Otherwise I would not bet a penny on a smalltalk dialect.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;http:&#x2F;&#x2F;tulipemoutarde.be&#x2F;documents&#x2F;blog-files&#x2F;squeak4.3.png&quot; alt=&quot;Squeak 4.3 pre&quot; &#x2F;&gt;
&lt;img src=&quot;http:&#x2F;&#x2F;tulipemoutarde.be&#x2F;documents&#x2F;blog-files&#x2F;pharo1.4.png&quot; alt=&quot;Pharo 1.4 pre&quot; &#x2F;&gt;
&lt;img src=&quot;http:&#x2F;&#x2F;tulipemoutarde.be&#x2F;documents&#x2F;blog-files&#x2F;visualworks.jpg&quot; alt=&quot;Visualworks on MacOS&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Long story short, don&amp;rsquo;t use Smalltalk if you want to be the next WordPad or iTunes.&lt;&#x2F;p&gt;
&lt;p&gt;I&amp;rsquo;m not saying that Smalltalk is bad at user interfaces, new UI paradigms are tested with Smalltalk. &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Croquet_Project&quot;&gt;Croquet&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;newspeaklanguage.org&#x2F;&quot;&gt;Newspeak&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;gaucho.inf.usi.ch&#x2F;&quot;&gt;Gaucho&lt;&#x2F;a&gt; are examples of some innovations in user interfaces (one for collaborating in 3D world, the other for IDE and GUI framework).&lt;&#x2F;p&gt;
&lt;p&gt;footnote: I actually have to mention that I&amp;rsquo;ve heard that &lt;a href=&quot;http:&#x2F;&#x2F;www.object-arts.com&#x2F;&quot;&gt;Dolphin&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;www.cincomsmalltalk.com&#x2F;main&#x2F;products&#x2F;objectstudio&#x2F;&quot;&gt;ObjectStudio&lt;&#x2F;a&gt; runs natively fine on windows.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Smalltalk for the Rubyist</title>
		<published>2011-12-09T10:55:00+00:00</published>
		<updated>2011-12-09T10:55:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-09-smalltalk-for-the-rubyist-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-09-smalltalk-for-the-rubyist-html/</id>
		<content type="html">&lt;p&gt;After my previous post about the &lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2011-12-06-the-pharo-smalltalk-ecosystem-html&#x2F;&quot;&gt;Pharo
ecosystem&lt;&#x2F;a&gt;, some people
asked me more about a comparison of Smalltalk and Ruby. And how a Rubyist could
leverage his knowledge when learning Smalltalk.&lt;&#x2F;p&gt;
&lt;p&gt;The two languages are class based, dynamic and their supporters like their clean
and easy syntax. Actually, Smalltalk is sometimes considered as one of the
father of Ruby. They share quite a lot and most of the patterns used in one can
be easily expressed in the other.&lt;&#x2F;p&gt;
&lt;p&gt;This post does not cover the basic syntax of Smalltalk. If you want to learn it
(15 minutes max), &lt;a
href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Smalltalk#Syntax&quot;&gt;wikipedia&lt;&#x2F;a&gt; should be
enough.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementations&quot;&gt;Implementations&lt;&#x2F;h2&gt;
&lt;p&gt;Ruby comes in different flavors: MRI, YARV, &lt;a
href=&quot;http:&#x2F;&#x2F;rubini.us&#x2F;&quot;&gt;Rubinius&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;jruby.org&#x2F;&quot;&gt;JRuby&lt;&#x2F;a&gt;, &lt;a
href=&quot;http:&#x2F;&#x2F;maglev.github.com&#x2F;&quot;&gt;Maglev&lt;&#x2F;a&gt;, etc. So does Smalltalk. The
principal difference is that they are no “official” distribution.
Every dialect has its own ecosystem and tools. Some are open source, some are
proprietary.&lt;&#x2F;p&gt;
&lt;p&gt;Choosing an implementation can be a quite challenging task. If you want to go
the open source way:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;squeak.org&#x2F;&quot;&gt;Squeak&lt;&#x2F;a&gt;, the most famous implementation. The
project has quite a long history. The development seems to have slowed down a
bit 3-4 years ago but Squeakers are working hard now.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;home&quot;&gt;Pharo&lt;&#x2F;a&gt;, a fork of Squeak. The
goal of the Pharoers is to produce a clean and industry-capable Smalltalk. It
all started when some people were really pissed off by the inaction of the
Squeak community. Backward compatibility was a pretext for doing nothing.
Pharo moves fast and does not aim to stay backward compatible with Squeak.
Many projects still runs on the two without a itch though.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;smalltalk.gnu.org&#x2F;&quot;&gt;GNU Smalltalk&lt;&#x2F;a&gt;, an alien
implementation. You can use your favorite text editor with it. It is a clean
implementation but it maybe misses a complete environment.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;amber-lang.net&#x2F;&quot;&gt;Amber&lt;&#x2F;a&gt;, a smalltalk that compiles to
Javascript. Pretty young but already impressive. It can be used with Node.js
or in the browser.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’m not really interested in proprietary implementations but there are
three big players in that field: &lt;a
href=&quot;http:&#x2F;&#x2F;www.cincomsmalltalk.com&#x2F;main&#x2F;&quot;&gt;Cincom Smalltalk&lt;&#x2F;a&gt;, &lt;a
href=&quot;http:&#x2F;&#x2F;www.instantiations.com&#x2F;products&#x2F;vasmalltalk&#x2F;index.html&quot;&gt;VA
Smalltalk&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;gemstone.com&#x2F;products&#x2F;gemstone&quot;&gt;Gemstone&#x2F;S&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Gemstone is not only a Smalltalk implementation but also an extremly scalable
object-database. Actually &lt;a href=&quot;http:&#x2F;&#x2F;maglev.github.com&#x2F;&quot;&gt;Maglev&lt;&#x2F;a&gt; is a
Gemstone based products. If you’re serious about Ruby, you should
definitely give Maglev a look.&lt;&#x2F;p&gt;
&lt;p&gt;My favorite implementation is Pharo. I like the energy in the community and its
direction. It is for me the best bet for the future. It very similar to squeak
but this screenshot of the main menu is enough to convince me.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img
src=&quot;http:&#x2F;&#x2F;tulipemoutarde.be&#x2F;documents&#x2F;blog-files&#x2F;squeak4.2-pharo1.4-menu.png&quot;
alt=&quot;Pharo 4.2 and Pharo 1.4 world menu&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can follow &lt;a
href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;8426981&#x2F;squeak-or-pharo-for-the-beginning-smalltalker&quot;&gt;this
thread on stackoverflow&lt;&#x2F;a&gt; to get the opinions of others.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-environment&quot;&gt;The Environment&lt;&#x2F;h2&gt;
&lt;p&gt;Here comes the biggest problem when learning Smalltalk. That’s where
people usually get lost. Smalltalk code does not lie on a plain text file. There
are literally no “code time”, it’s always runtime. It would be
like coding in an IRB session. You manipulate objects all the time. Consequences
?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;You can inspect object in live. You are working with a webservice and want to
inspect the answer? Just inspect the response.&lt;&#x2F;li&gt;
&lt;li&gt;Change values on the fly. You wanna know what happens if that variable is &lt;code&gt;-5&lt;&#x2F;code&gt;
instead of &lt;code&gt;5&lt;&#x2F;code&gt;? Change its value to see what happens.&lt;&#x2F;li&gt;
&lt;li&gt;You can actually code in the debugger. The debugger (or a stacktrace) is not
an analysis tool anymore. You can actually code in it. A method is missing?
Oops. Create it on the fly and continue the execution from where it failed.&lt;&#x2F;li&gt;
&lt;li&gt;Fast tests, all the time. &lt;a href=&quot;http:&#x2F;&#x2F;coreyhaines.com&#x2F;&quot;&gt;Corey Haines&lt;&#x2F;a&gt;
teaches you how to get &lt;a
  href=&quot;http:&#x2F;&#x2F;arrrrcamp.be&#x2F;videos&#x2F;2011&#x2F;corey-haines+++fast-rails-tests&#x2F;&quot;&gt;fast
tests&lt;&#x2F;a&gt; in rails. You do not need this in Smalltalk as your
web&#x2F;test&#x2F;whatever framework are &lt;em&gt;already loaded&lt;&#x2F;em&gt;. Of course, if your
tests starts to rely on external depencies (disk&#x2F;network&#x2F;etc) without mocking,
they’ll get slow. No surprises.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Actually some tools are starting to appear in Ruby. &lt;a
href=&quot;http:&#x2F;&#x2F;pry.github.com&#x2F;&quot;&gt;Pry&lt;&#x2F;a&gt; is pretty damn cool Ruby tool. Once
you’ll get used to Smalltalk environments you’ll want more.&lt;&#x2F;p&gt;
&lt;p&gt;When you load a library in your image, it lies next to your code. You can then
read it, inspect it, put breakpoint in it and do whatever you want with it.&lt;&#x2F;p&gt;
&lt;p&gt;An image contains your code and all the libraries you want. It acts as a
container and is completely independent from other images.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;metaprogramming-object-and-classes&quot;&gt;Metaprogramming, Object and Classes&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, that one is tricky. What do you expect from meta-programming?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Adding methods on runtime? You are already in runtime.&lt;&#x2F;li&gt;
&lt;li&gt;Handle &lt;code&gt;method_missing&lt;&#x2F;code&gt;? Welcome &lt;code&gt;doesNotUnderstand&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As &lt;code&gt;method_missing&lt;&#x2F;code&gt; in Ruby, &lt;code&gt;doesNotUnderstand&lt;&#x2F;code&gt; must be used carefully. The
usual advice applies in Smalltalk.&lt;&#x2F;p&gt;
&lt;p&gt;Actually defining a class in Smalltalk is just sending a message (“calling
a method” in Smalltalk jargon) to the class &lt;code&gt;Object&lt;&#x2F;code&gt;. Adding a method is
also a matter of sending a message to define it. The only difference is that you
use tools to do it. Remember, it’s runtime and your environment is the
&lt;em&gt;running&lt;&#x2F;em&gt; your code. That living environment comes with great
responsibilities. If you try something along &lt;code&gt;Object := nil&lt;&#x2F;code&gt; I guess
you’re a footing yourself in the foot.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to learn more about the Smalltalk object system, I warmly recommend
the chapter 13 of the &lt;a href=&quot;http:&#x2F;&#x2F;pharobyexample.org&#x2F;&quot;&gt;Pharo By Example&lt;&#x2F;a&gt;
free book. If you don’t know that much about Ruby’s object system, I
recommend the &lt;a
href=&quot;http:&#x2F;&#x2F;scotland-on-rails.s3.amazonaws.com&#x2F;2A04_DaveThomas-SOR.mp4&quot;&gt;Dave
Thomas presentation&lt;&#x2F;a&gt; at Scotland on Rails 2009.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;returns&quot;&gt;Returns&lt;&#x2F;h2&gt;
&lt;p&gt;Methods need explicit returns (with &lt;code&gt;^&lt;&#x2F;code&gt;). If omitted, the method will return
self.&lt;&#x2F;p&gt;
&lt;p&gt;You get implicit returns for blocks: the value of the last instruction is the
the value returned by the block. If you return (with &lt;code&gt;^&lt;&#x2F;code&gt;) inside a block, it is
a return value for the method.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;syntax-convention&quot;&gt;Syntax Convention&lt;&#x2F;h2&gt;
&lt;p&gt;Methods name and variables are spelled in CamelCase. Abbreviations are usually
avoided. Smalltalk uses keyword based method name (as in Objective-C). Many Ruby
libraries&#x2F;framework mimic this by passing an hash as argument.&lt;&#x2F;p&gt;
&lt;p&gt;The tabs vs. spaces does not exist in the Smalltalk community. In every tool,
press &lt;code&gt;Tab&lt;&#x2F;code&gt; to indent and you’re done.&lt;&#x2F;p&gt;
&lt;p&gt;As usual, just keep the global syntax style of the project you’re working
on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usual-suspects&quot;&gt;Usual suspects&lt;&#x2F;h2&gt;
&lt;p&gt;Be careful when using cascades, a common is mistake is the following:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;programmingLanguages := OrderedCollection new
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Ruby&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Java&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Haskell&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the end of the execution, programmingLanguages will be the String &lt;code&gt;Haskell&lt;&#x2F;code&gt;.
That’s because the method &lt;code&gt;add:&lt;&#x2F;code&gt; returns its argument, not &lt;code&gt;self&lt;&#x2F;code&gt;. To
prevent this, send &lt;code&gt;yourself&lt;&#x2F;code&gt; at the end of the cascade:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;programmingLanguages := OrderedCollection new
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Ruby&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Java&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  add: &amp;#39;Haskell&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  yourself.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another trick of the the language is the evaluation order:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;  3 + 4 * 5  #=&amp;gt; 35 and not 23
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Evaluation is done from left to right. Mathematical order is not preserved.
Indeed, &lt;code&gt;+&lt;&#x2F;code&gt; and &lt;code&gt;*&lt;&#x2F;code&gt; are simple methods. Smalltalk does not even know (and does
not care) that it is executing mathematical instructions. You must use
parenthesis to express precedence:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;  3 + ( 4 * 5 ) #=&amp;gt; 23&amp;lt;&#x2F;pre&amp;gt;&amp;lt;&#x2F;div&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;version-control&quot;&gt;Version Control&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;tulipemoutarde.be&#x2F;posts&#x2F;2011-12-06-the-pharo-smalltalk-ecosystem-html&#x2F;&quot;&gt;My previous post&lt;&#x2F;a&gt; will
explain you how to version Smalltalk code. Do not expect &lt;code&gt;Git&lt;&#x2F;code&gt;, &lt;code&gt;Mercurial&lt;&#x2F;code&gt; or
&lt;code&gt;Subversion&lt;&#x2F;code&gt; (although they can be used as backends for Monticello).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Once again, this post is inspired by someone else doing &lt;a
href=&quot;http:&#x2F;&#x2F;tore.darell.no&#x2F;pages&#x2F;javascript_eye_for_the_ruby_guy&quot;&gt;the same for
Javascript&lt;&#x2F;a&gt; (thanks Greg Spurrier for the link). The &lt;a
href=&quot;http:&#x2F;&#x2F;squeakbyexample.org&#x2F;&quot;&gt;Squeak by Example&lt;&#x2F;a&gt; or &lt;a
href=&quot;http:&#x2F;&#x2F;pharobyexample.org&#x2F;&quot;&gt;Pharo By Example&lt;&#x2F;a&gt; books are worth to read.
Beware that the tools described in the book are sometimes outdated but the
principles are still perfectly valid.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The Pharo Smalltalk ecosystem</title>
		<published>2011-12-06T03:00:00+00:00</published>
		<updated>2011-12-06T03:00:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-12-06-the-pharo-smalltalk-ecosystem-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-12-06-the-pharo-smalltalk-ecosystem-html/</id>
		<content type="html">&lt;p&gt;This post is intented to developers who’ve heard that Smalltalk is hot and sexy. A fraction of them have tried to download a &lt;a href=&quot;https:&#x2F;&#x2F;gforge.inria.fr&#x2F;frs&#x2F;download.php&#x2F;29274&#x2F;Pharo-1.3-13315-OneClick.zip&quot;&gt;One-Click version of Pharo&lt;&#x2F;a&gt; and played a bit with the language by following a tutorial or two.&lt;&#x2F;p&gt;
&lt;p&gt;So now they have a taste of Smalltalk but they do not get the entire picture, how the environment work, how people actually build and deploy software with it. If you are one of them, you’ll probably want to take some time to read this :)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;images-and-vms&quot;&gt;Images and VMs&lt;&#x2F;h2&gt;
&lt;p&gt;If you’ve downloaded a One-Click image, you haven’t experimented with the notion of image and VM in Smalltalk. Actually you have but not in an explicit way, you’ve simply clicked on an icon and got your environment. You’ve maybe ‘Quit and Save’ and when reopening the application you had the same state than when you left. Easy.&lt;&#x2F;p&gt;
&lt;p&gt;In pratice, Pharo works with an image running on top of a virtual machine. If you come from another scripting language, it certainly offers a REPL (e.g., IRB for Ruby). Think of the image as a dump of that REPL at a given moment.&lt;&#x2F;p&gt;
&lt;p&gt;A Pharo image contains everything: your code, the tools and the libraries. You can load code into it, you can save it and restart it at any moment. This image is closed. That’s why you cannot use your text editor to edit Pharo code (actually you could but you certainly would not want that).&lt;&#x2F;p&gt;
&lt;p&gt;The VM is usually something you should not care about. My advice is to use the one given by the Pharo website, it is tested by a Jenkins server and is the one people use the most.&lt;&#x2F;p&gt;
&lt;p&gt;In a nutshell: download a VM and an image from &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;pharo-download]&quot;&gt;the official website&lt;&#x2F;a&gt;. At this moment, the stable version is Pharo 1.3 and the image is CogVM-13307. I personnaly put the VM in the &lt;code&gt;&#x2F;Applications&lt;&#x2F;code&gt; folder on my Mac. The image comes with a &lt;code&gt;.changes&lt;&#x2F;code&gt; and &lt;code&gt;.sources&lt;&#x2F;code&gt; files. Keep them in the same directory than your image.&lt;&#x2F;p&gt;
&lt;p&gt;Beware that the evolutions of the image and the VM are not tight. It is possible that a Pharo 1.3 image will run on a new VM version in two years.&lt;&#x2F;p&gt;
&lt;p&gt;To start an image, double-click on it. If your OS does not get it, you can drag the image icon on the VM icon. That should work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;version-numbers&quot;&gt;Version numbers&lt;&#x2F;h2&gt;
&lt;p&gt;When you download the image, you can see the exact version you are downloading: &lt;code&gt;Pharo-1.3-13315.zip&lt;&#x2F;code&gt;. It means that it is the 315th revision of Pharo 1.3. The 13xxx part is redundant with the Pharo-1.3.&lt;&#x2F;p&gt;
&lt;p&gt;The VM has currently the name &lt;code&gt;CogVM-Mac-13307.zip&lt;&#x2F;code&gt;. Which means it was frozen with the 307th revision of the Pharo image.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;source-version-control&quot;&gt;Source version control&lt;&#x2F;h2&gt;
&lt;p&gt;Your code is in the image. You don’t even have a full text view of your nice classes. How do you persist it? So far, you’ve probably save your image and re-open it later. That’s the best way to lose everything if your image crashes (and that happens). It’s also not really handy if you’re not alone on the project.&lt;&#x2F;p&gt;
&lt;p&gt;Monticello comes to the rescue. It is a version control system like Git, Subversion or Mercurial. The only difference is that it does not version files but classes and methods. That’s pretty great for an object-oriented language, isn’t it?&lt;&#x2F;p&gt;
&lt;p&gt;Historically, &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&quot;&gt;Squeaksource&lt;&#x2F;a&gt; is the &lt;a href=&quot;http:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt; of Smalltalk. It is old, ugly and slow but it works. A more modern alternative is &lt;a href=&quot;http:&#x2F;&#x2F;ss3.gemstone.com&#x2F;&quot;&gt;SqueakSource3&lt;&#x2F;a&gt;, which brings Squeaksource to the latest frameworks. There are less projects than in the original Squeaksource but you should use it for your new projects.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.smalltalkhub.com&#x2F;&quot;&gt;SmalltalkHub&lt;&#x2F;a&gt; is on its way. It is not stable enough to be used in production but we are all waiting for it :)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.jarober.com&#x2F;&quot;&gt;James Robertson&lt;&#x2F;a&gt; has made two (very short screencasts to help you get up and running. You won’t need more than 4 minutes to watch them.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;vimeo.com&#x2F;20016315&quot;&gt;Smalltalk For You, episode 48&lt;&#x2F;a&gt;, you’ll see how to save a package in a Monticello repository. Gives you all the basic information you need to know to use Monticello. Three minutes. That’s it.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;vimeo.com&#x2F;20105609&quot;&gt;Smalltalk For You, episode 49&lt;&#x2F;a&gt;, this screencast will show you how reload the code you saved in the previous screencast in a fresh image. A little more than one minute.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;load-external-libraries&quot;&gt;Load external libraries&lt;&#x2F;h2&gt;
&lt;p&gt;Loading code in your image is pretty easy. Open a Monticello Browser and add the repository from which you want to load code. Et voilà, done.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that sometimes, a package has dependencies. So you end up losing 4 hours only to track the dependencies of the package and to figure out a load order. Metacello was designed to help you.&lt;&#x2F;p&gt;
&lt;p&gt;A project can provide a “Metacello Configuration”. This configuration describes the dependencies and the load order of the project. Of course a configuration can load an other one. You can also tag versions of your project.&lt;&#x2F;p&gt;
&lt;p&gt;When you want to use a project, the first thing to do is to find its MetacelloConfiguration. As of today, the lookup to find a configuration is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Check if the project exists in &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;MetacelloRepository.html&quot;&gt;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;MetacelloRepository.html&lt;&#x2F;a&gt;. This repo is a goldmine.&lt;&#x2F;li&gt;
&lt;li&gt;If it is not there, check in the project repository if you find a &lt;code&gt;ConfigurationOfTheProject&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Ask the Pharo-users mailing list.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If your project is not trivial, you should write a ConfigurationOfYourProject. You can get inspiration from other configurations. I personnaly like the ConfigurationOfFuel.&lt;&#x2F;p&gt;
&lt;p&gt;Once again, James Robertson has already covered the subject in his Smalltalk For You screencast series. &lt;a href=&quot;http:&#x2F;&#x2F;vimeo.com&#x2F;23666930&quot;&gt;Episode 82&lt;&#x2F;a&gt; shows you how to load GlorpDBX (an object-relational mapping package for Smalltalk) in a fresh image using Metacello Configuration in a little more than two minutes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;good-practices&quot;&gt;Good practices&lt;&#x2F;h2&gt;
&lt;p&gt;Ok, so now you know the tools that are used by Pharo developers. Let’s move on to the next critical point: Good habits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-image-everyday&quot;&gt;New image everyday&lt;&#x2F;h2&gt;
&lt;p&gt;As you save your image and reopen it 16 hours later in exactly the same state, you are probably tempted to keep it forever and do all your development in it. So convenient.&lt;&#x2F;p&gt;
&lt;p&gt;In theory only. With time, you experiment and create a bunch of stuff you won’t need. You have loaded  many external packages and you don’t know anymore which are your dependencies. Your image becomes bloated, it may eventually crash.&lt;&#x2F;p&gt;
&lt;p&gt;The best way to avoid rotten images is to get a new one everyday. Download a stock Pharo image (or keep one somewhere locally) and load your MetacelloConfiguration. This will have two benefits:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Your image is always clean and not bloated.&lt;&#x2F;li&gt;
&lt;li&gt;You know that your code load and works. This way you are sure that your co-workers can load your code and deployment is smooth.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;keep-your-images-organized&quot;&gt;Keep your images organized&lt;&#x2F;h2&gt;
&lt;p&gt;I’m sure you’ve already think about it but try to keep your different images organized. it is not hard to end up with dozens of Pharo images scattered across your hard drive. Try to keep things simple. For example, I keep a directory with all my stock images (Pharo 1.2, 1.3, the preversion of 1.4, Squeak, One-Clicks, etc).&lt;&#x2F;p&gt;
&lt;p&gt;Choose a convention and stick to it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;syntax-conventions-micro-decisions&quot;&gt;Syntax conventions &amp;amp; micro decisions&lt;&#x2F;h2&gt;
&lt;p&gt;Follow the conventions used by many Smalltalkers. Naming conventions as well as indentation. A &lt;em&gt;very&lt;&#x2F;em&gt; good read is &lt;a href=&quot;http:&#x2F;&#x2F;www.amazon.com&#x2F;Smalltalk-Best-Practice-Patterns-Kent&#x2F;dp&#x2F;013476904X&#x2F;ref=sr_1_1?ie=UTF8&amp;amp;qid=1323126529&amp;amp;sr=8-1&quot;&gt;Smalltalk Best Practices Patterns&lt;&#x2F;a&gt; by Kent Beck. Follow this style your code will follow Smalltalk idioms. Actually, the patterns discussed are also valid for Ruby. So go and grab your copy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I wanted to write this guide for a long time now. This &lt;a href=&quot;http:&#x2F;&#x2F;mirnazim.org&#x2F;writings&#x2F;python-ecosystem-introduction&#x2F;&quot;&gt;article&lt;&#x2F;a&gt; for Python convinced me to post it.&lt;&#x2F;p&gt;
&lt;p&gt;I hope it will be useful for some folks who want to try Smalltalk (and its Pharo implementation). Feel free to email me or to comment if you have any question or suggestion. If you are a Ruby developer wanting to learn Smalltalk, please &lt;a href=&quot;mailto:tulipemoutarde@gmail.com&quot;&gt;drop me an email&lt;&#x2F;a&gt;, I need your help for future posts !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Available for work!</title>
		<published>2011-11-16T10:54:00+00:00</published>
		<updated>2011-11-16T10:54:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-11-16-available-for-work-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-11-16-available-for-work-html/</id>
		<content type="html">&lt;p&gt;As I&#x27;m getting more and more addicted to Pharo Smalltalk, I would like to offer my services as a&amp;nbsp; Smalltalk developer.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m a freelance contractor with a belgian VAT number but I also have a valid working permit for Canada (I&#x27;m currently living in Vancouver, BC).&lt;&#x2F;p&gt;
&lt;p&gt;If you are looking for a part-time developer with a Ruby&#x2F;Rails&#x2F;Javascript  background, do not hesitate to contact me (even for a chat), I&#x27;m all  ears!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo development</title>
		<published>2011-10-10T14:34:00+00:00</published>
		<updated>2011-10-10T14:34:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-10-10-pharo-development-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-10-10-pharo-development-html/</id>
		<content type="html">&lt;p&gt;I sometimes wonder why &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;&quot;&gt;Pharo&lt;&#x2F;a&gt; has such difficulties to get a stable version. Even when a release comes out, it is not that rock solid.&lt;&#x2F;p&gt;
&lt;p&gt;When building an image, you get code from various locations. Integrating everything together seems hard. For example, a package will use a syntax highlighting mechanism, which will be different that the one used in another package. Different shape, different quality, different patterns, it is hard to get the same foundation for everything when you cover many areas: gui, drawing, threads, locks, filesystem, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Smalltalk acts as a whole operating system, it is one of its strength but also one of its weakness. It sounds wrong when you are used to the Unix philosophy where one tools equals one function. Smalltalk breaks that and want to do everything by itself. It becomes nice when you want to do something that crosses different layers (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tobi&#x2F;delayed_job&quot;&gt;delayed_job&lt;&#x2F;a&gt; would be almost useless in Smalltalk); you start your image and everything runs inside it. You stop it, everything stops. Easy. The drawback is obvious: Smalltalk environments tend to reinvent the wheel all the time.&lt;&#x2F;p&gt;
&lt;p&gt;When you consider this, you start to realize the tremendous amount of work done by the developers. They proceed by baby steps but they are going very far&amp;hellip; And I can&amp;rsquo;t wait to use &lt;a href=&quot;http:&#x2F;&#x2F;rmod.lille.inria.fr&#x2F;coral&#x2F;index.html&quot;&gt;Pharo for system scripting&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Ruby frustration</title>
		<published>2011-09-30T12:15:00+00:00</published>
		<updated>2011-09-30T12:15:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-09-30-ruby-frustration-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-09-30-ruby-frustration-html/</id>
		<content type="html">&lt;p&gt;The more I code in Smalltalk, the more I find the flow of developing in Ruby annoying. What I really miss is a good way to navigate code, the debugging facilities and the runtime aspect of a Smalltalk dialect.&lt;&#x2F;p&gt;
&lt;h2&gt;Code navigation&lt;&#x2F;h2&gt;
&lt;p&gt;The browser is the standard way to browse code in Smalltalk. While it can be seen as cumbersome and ugly (in the look and the feel) compared to a native UI or a text editor, experienced smalltalkers have a love-hate relationship with their browser.&lt;&#x2F;p&gt;
&lt;p&gt;When using it, you do not need to have 45 tabs opened in your web browser. Almost all the documentation you need is right there in front of you. Browsing the senders and implementors of a method is so easy and convenient. When you come back to a text editor and Ruby code it&amp;rsquo;s just a pain in the ass to perform changes in your code.&lt;&#x2F;p&gt;
&lt;p&gt;As a developer you will spend (by far) much more time debugging and reading code than writing it, why not have a dedicated tool to browse it ?&lt;&#x2F;p&gt;
&lt;h2&gt;Runtime&lt;&#x2F;h2&gt;
&lt;p&gt;One of the most frustrating point when developing in Rails is how slow it becomes when your Gemfile grows. Running the test suite is so slow, it feels like the old &amp;lsquo;code-compile-run&amp;rsquo; cycle is back again. It&amp;rsquo;s not the tests that are slow per se but loading the environment. Each time you run a test, you wait for Rails to start while the actual time spent in the test(s) is negligible. Very frustrating when doing TDD.&lt;&#x2F;p&gt;
&lt;p&gt;There are some tools to overcome this problem but it&amp;rsquo;s sometimes quite hard to get them working (more on this in a later post).&lt;&#x2F;p&gt;
&lt;h2&gt;Debugging&lt;&#x2F;h2&gt;
&lt;p&gt;Take the browsing tools and the always-runtime feature and you get easy debugging. The TDD flow get much better when you can create methods on the fly, navigate the stack and change the state of your object on the fly. In Rails, I&amp;rsquo;m used to run the test, see it fails, switch to my text editor and re-run the test. Tools like &lt;a href=&quot;http:&#x2F;&#x2F;pry.github.com&#x2F;&quot;&gt;Pry&lt;&#x2F;a&gt; makes things much more smooth but they are quite far from a live debugger.&lt;&#x2F;p&gt;
&lt;h2&gt;Closing&lt;&#x2F;h2&gt;
&lt;p&gt;This post is already far too long for and probably not very well illustrated but I hope you get the idea. I&amp;rsquo;m not saying that Smalltalk is better; all the goodness mentioned before have their drawbacks, mainly when it comes to deployment. As your code is always running, it can be quite cumbersome to deploy it on a server in a fresh state. There are tools to help but they are not as nice as what you get in the Ruby world. A lot of smalltalkers seem to have their own recipes to deploy. It can be quite disturbing for someone coming from Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, I gonna try to illustrate my arguments in the next posts. Thanks for reading !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Seaside session timeout</title>
		<published>2011-08-28T13:27:00+00:00</published>
		<updated>2011-08-28T13:27:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-08-28-seaside-session-timeout-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-08-28-seaside-session-timeout-html/</id>
		<content type="html">&lt;p&gt;As usual, this post is most a reminder for myself but it can be useful for others. In previous version of Seaside (prior to 3.0), it was possible to change the default session timeout by using:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;application preferencesAt: #sessionExpirySecond put: 1200
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It has changed with Seaside 3.0 and looked a bit more complicated now:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;application cache expiryPolicy configuration
&lt;&#x2F;span&gt;&lt;span&gt;  at: #cacheTimeout
&lt;&#x2F;span&gt;&lt;span&gt;  put: 1200
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If I&amp;rsquo;m missing something, &lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;fstephany&quot;&gt;tweet me&lt;&#x2F;a&gt; :)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Metacello configurations readability</title>
		<published>2011-08-24T07:46:00+00:00</published>
		<updated>2011-08-24T07:46:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-08-24-metacello-configurations-readability-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-08-24-metacello-configurations-readability-html/</id>
		<content type="html">&lt;p&gt;I&amp;rsquo;m polishing a &lt;em&gt;very&lt;&#x2F;em&gt; small package to interact with &lt;a href=&quot;http:&#x2F;&#x2F;www.ogone.be&quot;&gt;ogone&lt;&#x2F;a&gt;, a payment platform, from a &lt;a href=&quot;http:&#x2F;&#x2F;seaside.st&#x2F;&quot;&gt;Seaside&lt;&#x2F;a&gt; application. So it&amp;rsquo;s time to write a Metacello configuration to share it easily.&lt;&#x2F;p&gt;
&lt;p&gt;I always have hard time to read Metacello configurations and wonder if a vertical alignment wouldn&amp;rsquo;t help. Basically, I find this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;baseline10: spec
&lt;&#x2F;span&gt;&lt;span&gt;  spec for: #common do: [
&lt;&#x2F;span&gt;&lt;span&gt;    spec blessing: #baseline.
&lt;&#x2F;span&gt;&lt;span&gt;    spec
&lt;&#x2F;span&gt;&lt;span&gt;      repository: &amp;#39;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;ogone&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Core&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Seaside-Example&amp;#39; with: [spec requires: &amp;#39;Ogone-Core&amp;#39;];
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Tests&amp;#39;           with: [spec requires: &amp;#39;Ogone-Core&amp;#39;].
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    spec
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;default&amp;#39;         with: #(&amp;#39;Core&amp;#39; &amp;#39;Seaside-Example&amp;#39; &amp;#39;Test&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Core&amp;#39;            with: #(&amp;#39;Ogone-Core&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Seaside-Example&amp;#39; with: #(&amp;#39;Ogone-Core&amp;#39; &amp;#39;Ogone-Seaside-Example&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Tests&amp;#39;           with: #(&amp;#39;Ogone-Core&amp;#39; &amp;#39;Ogone-Test&amp;#39;)
&lt;&#x2F;span&gt;&lt;span&gt;  ].
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;More readable than this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;baseline10: spec
&lt;&#x2F;span&gt;&lt;span&gt;  spec for: #common do: [
&lt;&#x2F;span&gt;&lt;span&gt;    spec blessing: #baseline.
&lt;&#x2F;span&gt;&lt;span&gt;    spec
&lt;&#x2F;span&gt;&lt;span&gt;      repository: &amp;#39;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;ogone&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Core&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Seaside-Example&amp;#39; with: [spec requires: &amp;#39;Ogone-Core&amp;#39;];
&lt;&#x2F;span&gt;&lt;span&gt;      package: &amp;#39;Ogone-Tests&amp;#39; with: [spec requires: &amp;#39;Ogone-Core&amp;#39;].
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    spec
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;default&amp;#39; with: #(&amp;#39;Core&amp;#39; &amp;#39;Seaside-Example&amp;#39; &amp;#39;Test&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Core&amp;#39; with: #(&amp;#39;Ogone-Core&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Seaside-Example&amp;#39; with: #(&amp;#39;Ogone-Core&amp;#39; &amp;#39;Ogone-Seaside-Example&amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;      group: &amp;#39;Tests&amp;#39; with: #(&amp;#39;Ogone-Core&amp;#39; &amp;#39;Ogone-Test&amp;#39;)
&lt;&#x2F;span&gt;&lt;span&gt;  ].
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Am I the only one ?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Too much Smalltalk</title>
		<published>2011-08-13T12:15:00+00:00</published>
		<updated>2011-08-13T12:15:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-08-13-too-much-smalltalk-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-08-13-too-much-smalltalk-html/</id>
		<content type="html">&lt;p&gt;I&amp;rsquo;m using way too much Smalltalk these days, I find myself typing:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;@articles do |each|
&lt;&#x2F;span&gt;&lt;span&gt;  # do something with each
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;instead of:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;@articles.each do |article|
&lt;&#x2F;span&gt;&lt;span&gt;  # do something with article
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;when coding in Ruby. Stupid brain&amp;hellip;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo Smalltalk experience report, part I</title>
		<published>2011-08-11T11:34:05+00:00</published>
		<updated>2011-08-11T11:34:05+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-08-11-pharo-smalltalk-experience-report-part-i-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-08-11-pharo-smalltalk-experience-report-part-i-html/</id>
		<content type="html">&lt;p&gt;Hi there, I&amp;rsquo;d like to share some of my latest experiments with &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;home&quot;&gt;Pharo&lt;&#x2F;a&gt;. This post is not very well structured and certainly needs some polishing but time is scarce.&lt;&#x2F;p&gt;
&lt;p&gt;I use Ruby and Rail for my daily work at &lt;a href=&quot;http:&#x2F;&#x2F;agilitic.com&quot;&gt;agilitic&lt;&#x2F;a&gt;. I&amp;rsquo;ve always dabbled with Smalltalk (Squeak then Pharo) and wanted to build a real world project with it. &lt;a href=&quot;http:&#x2F;&#x2F;wapict.be&quot;&gt;Wapict.be&lt;&#x2F;a&gt; was the ideal candidate: not too big while not trivial.&lt;&#x2F;p&gt;
&lt;p&gt;The idea behind wapict is simple: become the reference of photography in &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wallonie_Picarde&quot;&gt;Wallonie-Picarde&lt;&#x2F;a&gt;, a region of Belgium. We sell stock pictures in digital or printed format, provide photographers for events and experiment with photography techniques&amp;hellip;&lt;&#x2F;p&gt;
&lt;p&gt;It started with a simple presentation website and has now some nice features for photographers. A lot more is planned (e.g., buy online with credit card) but the project is advanced enough to do a first post about it.&lt;&#x2F;p&gt;
&lt;h2&gt;Stack&lt;&#x2F;h2&gt;
&lt;p&gt;Currently, wapict is running with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Pharo 1.3&lt;&#x2F;li&gt;
&lt;li&gt;Seaside 3.0.5&lt;&#x2F;li&gt;
&lt;li&gt;XMLSupport&lt;&#x2F;li&gt;
&lt;li&gt;Fuel 1.4&lt;&#x2F;li&gt;
&lt;li&gt;Zinc HTTP server&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All managed via &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;metacello&#x2F;&quot;&gt;Metacello&lt;&#x2F;a&gt; Configurations.&lt;&#x2F;p&gt;
&lt;p&gt;The project runs with the &lt;a href=&quot;http:&#x2F;&#x2F;www.mirandabanda.org&#x2F;files&#x2F;Cog&#x2F;VM&#x2F;&quot;&gt;Cog VMs&lt;&#x2F;a&gt;. Development is done on MacOS while the staging and production servers are running Linux. A big problem with Pharo is that there are no official supported VMs. You are there on your own and choosing a suitable VM can be tedious. Hopefully this will change in the future.&lt;&#x2F;p&gt;
&lt;h2&gt;Persistence&lt;&#x2F;h2&gt;
&lt;p&gt;The traffic is quite low and a single Pharo image can handle the load while sipping a coffee. Persistence is primitive right now: I serialize everything with Fuel on disk. Nothing really fancy but it works well for what I need.&lt;&#x2F;p&gt;
&lt;p&gt;Pictures are stored on disk and are served with Nginx. The originals are kept private and are not accessible from the public.&lt;&#x2F;p&gt;
&lt;h2&gt;Deployment&lt;&#x2F;h2&gt;
&lt;p&gt;At work we use Git + Capistrano or Vlad to deploy our rails applications. My usual flow is as simple as:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;git pull
&lt;&#x2F;span&gt;&lt;span&gt;git commit -am &amp;amp;quot;fixed bug #456&amp;amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;git push
&lt;&#x2F;span&gt;&lt;span&gt;cap staging deploy
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and hopla my code is in staging. Once validated, `cap production deploy` deploys on the production box. Easy.&lt;&#x2F;p&gt;
&lt;p&gt;It seems that there are no equivalent on Pharo or at least there are no common workflow, everybody has his own recipe to roll out new code.&lt;&#x2F;p&gt;
&lt;p&gt;I have added a link in the admin section that loads the latest stable Metacello release available. So my deployment flow is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;commit modified packages&lt;&#x2F;li&gt;
&lt;li&gt;update and commit metacello configuration&lt;&#x2F;li&gt;
&lt;li&gt;login to the application and click on the update link.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Not too bad but I have to leave my Smalltalk environment to deploy. I&amp;rsquo;ll probably create a small webservice to perform administrative operations on the deployed image.&lt;&#x2F;p&gt;
&lt;h2&gt;Tools&lt;&#x2F;h2&gt;
&lt;p&gt;I only use the tools shipped with Pharo 1.3. Nothing really fancy but they work well. The default for code highlighting and code completion suit me.&lt;&#x2F;p&gt;
&lt;p&gt;I rebuild my development image as often as possible. Two benefits: I&amp;rsquo;m sure the whole project is easily loadable in a fresh image all the time and the mess I introduce in my image when developing is cleaned.&lt;&#x2F;p&gt;
&lt;h2&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;All in all, i&amp;rsquo;m quite happy with Seaside and Pharo. It is really refreshing to work with those when doing Ruby and Rails all the day. I cannot stand Rails when it comes to flow anymore. It just doesn&amp;rsquo;t feel right. I love to develop web applications with Javascript: I can code the behaviour much more easily than with plain HTTP requests and I feel this kind of joy when developing with Seaside.&lt;&#x2F;p&gt;
&lt;p&gt;What I really miss though is the possibility to login and open an IRB on a server. That&amp;rsquo;s quite dangerous in production but it helps a lot when checking the state of an application. What would be &lt;em&gt;really&lt;&#x2F;em&gt; nice to have is a set of remote tools to browse and debug an image from the outside. Some uses RFB to do that but I find it clumsy and slow.&lt;&#x2F;p&gt;
&lt;p&gt;I&amp;rsquo;ve recently discovered &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;tode&#x2F;&quot;&gt;tODE&lt;&#x2F;a&gt;, a development environment that runs on top of Seaside, I haven&amp;rsquo;t checked it yet but Dale Henrichs use it for 80% of his development.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, my dream is pretty simple: Pharo 1.4 with &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Ring-model-infrastructure-for-Pharo-td3081971.html&quot;&gt;Ring&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;rmod.lille.inria.fr&#x2F;coral&#x2F;index.html&quot;&gt;Coral&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Seaside-on-Pharo-Kernel-td3729573.html&quot;&gt;remote tools&lt;&#x2F;a&gt; =)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Dynamically add&#x2F;remove the Seaside&#x27;s toolbar on an application</title>
		<published>2011-07-13T14:04:00+00:00</published>
		<updated>2011-07-13T14:04:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-07-13-dynamically-addremove-the-seasides-toolbar-on-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-07-13-dynamically-addremove-the-seasides-toolbar-on-html/</id>
		<content type="html">&lt;p&gt;I wanted to display or hide the tool bar on a Seaside application. It turned out to be pretty simple.&lt;&#x2F;p&gt;
&lt;p&gt;To remove it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;app configuration
&lt;&#x2F;span&gt;&lt;span&gt;   at: #rootDecorationClasses
&lt;&#x2F;span&gt;&lt;span&gt;   addAll: #()
&lt;&#x2F;span&gt;&lt;span&gt;   removeAll: (Array with: WAToolDecoration)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And to show it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;app configuration
&lt;&#x2F;span&gt;&lt;span&gt;    at: #rootDecorationClasses
&lt;&#x2F;span&gt;&lt;span&gt;    addAll: (Array with: WAToolDecoration)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another useful snippet to retrieve an application from its name:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;WAAdmin defaultDispatcher handlerAt: &amp;#39;wapict&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Seasiders won&amp;rsquo;t find this exciting but this post is more a reminder for myself than anything else. If I&amp;rsquo;m doing something overcomplicated for nothing, shout my ignorance in the comments ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo mailing list weekly summary #6 - Migration !</title>
		<published>2011-03-28T13:08:00+00:00</published>
		<updated>2011-03-28T13:08:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-03-28-pharo-mailing-list-weekly-summary-6-migration-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-03-28-pharo-mailing-list-weekly-summary-6-migration-html/</id>
		<content type="html">&lt;p&gt;Hey there,&lt;&#x2F;p&gt;
&lt;p&gt;As said earlier, the Pharo mailing list weekly summary is now hosted on &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;news&quot;&gt;the main Pharo website&lt;&#x2F;a&gt; (which is powered by &lt;a href=&quot;http:&#x2F;&#x2F;www.cmsbox.com&#x2F;en&#x2F;cms&quot;&gt;Cmsbox&lt;&#x2F;a&gt;). The editing porcess is quite different from what I&#x27;m used to. Neat for someone who is not computer savvy but disturbing for someone who writes everything with Markdown!&lt;&#x2F;p&gt;
&lt;p&gt;As usual, I&#x27;ve probably forgotten some important topics, so do not hesitate to comment ;)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo mailing list weekly summary #5</title>
		<published>2011-03-12T06:48:00+00:00</published>
		<updated>2011-03-12T06:48:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-03-12-pharo-mailing-list-weekly-summary-5-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-03-12-pharo-mailing-list-weekly-summary-5-html/</id>
		<content type="html">&lt;p&gt;Once again, the week was very busy in the Pharo mailing list. It seems that Pharo 1.2 release is imminent. I skipped a massive amount of threads in this summary. If I removed something important for you, just shout and I&amp;rsquo;ll edit this post.&lt;&#x2F;p&gt;
&lt;p&gt;Next week, the &lt;em&gt;Pharo mailing list weekly summary&lt;&#x2F;em&gt; will move to the &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;&quot;&gt;official Pharo website&lt;&#x2F;a&gt;. Yeah !&lt;&#x2F;p&gt;
&lt;h2&gt;Events&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;en.inria.fr&#x2F;inria-research-centre&#x2F;lille-nord-europe&#x2F;calendar&#x2F;smalltalk&quot;&gt;Deep into Smalltalk&lt;&#x2F;a&gt; took place this week, about 45 people attended. It seems that Mariano &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;THANKS-a-lot-for-the-awesome-Deep-Smalltalk-School-td3349178.html&quot;&gt;enjoyed&lt;&#x2F;a&gt; it very much! Presentation slides are available and courses were recorded. Videos are not there yet but I&amp;rsquo;ll update this post as soon as they are.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Announcements&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.tudorgirba.com&#x2F;&quot;&gt;Doru&lt;&#x2F;a&gt; announced the &lt;strong&gt;Glamorous Tool Project&lt;&#x2F;strong&gt;. The goald is to build a set of Smalltalk development tools based on &lt;a href=&quot;http:&#x2F;&#x2F;www.moosetechnology.org&#x2F;tools&#x2F;glamour&quot;&gt;Glamour&lt;&#x2F;a&gt;. Is this the future of Pharo development tools ? &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;the-glamorous-toolkit-project-td3349849.html&quot;&gt;full thread&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;There is now an &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;cog&#x2F;&quot;&gt;issue tracker for Cog&lt;&#x2F;a&gt;. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-Cog-issue-tracker-td3347097.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Esteban released a new Cocoa VM: 5.7.4.1. This is a non Cog VM. This release adds no feature but small steps are better than big jumps. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-Cocoa-Squeak-VM-5-7-4-1-non-Cog-released-td3341972.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Umezawa-san told us that SIXX now works on Pharo 1.2 and Squeak 4.2. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Fwd-SIXX-in-Pharo-1-2-td3337674.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;InterpretorSimulator is now working with the latest images. Pavel warned us that it is far from perfect that it should work with small headless images. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;InterpreterSimulator-reloaded-td3342295.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Benjamin built a new Morphic widget: &amp;ldquo;SwitchableTreeWidget&amp;rdquo;. It should works fine on Pharo 1.2 (expect problems with 1.3). Load it and tell him what you think. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;New-widget-td3344098.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Discussions&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There are some discussions about using the SqueakSSL plugin with Pharo. That would help to use HTTPS. At the moment, &lt;a href=&quot;http:&#x2F;&#x2F;stunnel.org&#x2F;&quot;&gt;stunnel&lt;&#x2F;a&gt; is a possible solution. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Fwd-Https-Url-in-Pharo-1-2-td3337616.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;There are plans to bring Pharo in the Apple Store. The discussion moved to Apple vs the rest of the world and the future of computing and licensing questions. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-on-Apple-App-Store-td3334878.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Hilaire asked how to get bigger cursor in Pharo. Apparently Torsten has worked on this. full threads &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Bigger-cursor-td3339402.html&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Bigger-cursor-td3339843.html&quot;&gt;there&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Laurent is doing TDD for GUI development. There are no special tools for this and Laurent struggled a bit with `#visible` which always returns true. Ben showed the trick to detect if a window is closed. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Assert-SystemWindow-not-visible-td3330492.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef tried to install OSProcess in his image and ran into trouble. Beware that you need a VM with the OSProcess plugin. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;OSProcess-td3338691.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Alexandre explained different solution on how to run Smalltalk in a web browser.&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Kernel-td3335157i20.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Hilaire ran into trouble when installing DejaVuBitmapFonts on Pharo core 1.3. Fernando shared the snippet he uses. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Error-installing-DejaVuBitmapFonts-td3316606.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Problems with the integration process and the Hudson server for 1.2. &lt;em&gt;The Great and Perfect Release Cycle&lt;&#x2F;em&gt; is not an easy goal. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-1-2-and-test-failures-td3337119.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&amp;rsquo;s all folks, see you next week !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo mailing list weekly summary #4</title>
		<published>2011-03-05T13:03:00+00:00</published>
		<updated>2011-03-05T13:03:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-03-05-pharo-mailing-list-weekly-summary-4-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-03-05-pharo-mailing-list-weekly-summary-4-html/</id>
		<content type="html">&lt;p&gt;Here is the weekly summary of the Pharo project mailing list. If I missed something or say something wrong, please shout at me in the comments.&lt;&#x2F;p&gt;
&lt;p&gt;My hightlights of the week: at least three different project are in the tracks for a squeaksource replacement. Pharo 1.2 is almost out but everybody feels the need for a better infrastructure&#x2F;process. If you want to get involved on this side and if you have enough time, do not hesitate to send your ideas and contributions.&lt;&#x2F;p&gt;
&lt;h2&gt;Events&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pharo Sprint in Lille. Saturday 12th March. Tell if you plan to go ;) &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;About-the-sprint-saturday-12-td3333884.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;The sprint in Bern went very well. You can get an overview of what happened during the sprint on &lt;a href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;#!&#x2F;search&#x2F;pharosprint&quot;&gt;Twitter&lt;&#x2F;a&gt;. To keep it short, Camillo worked on &lt;em&gt;KeyMappings&lt;&#x2F;em&gt; (see &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-More-on-Keymappings-td3325569.html&quot;&gt;this thread&lt;&#x2F;a&gt; for more info), Lukas playing &lt;em&gt;WeakAnnouncements&lt;&#x2F;em&gt; and &lt;em&gt;OB&lt;&#x2F;em&gt;. Adrian, Jorge and Toon started a debugger based on Glamour. They worked hard to decouple the model from the GUI. Mircea built a new widget for searching multiple categories of items in the same time. All in all, Glamour becomes more and more important in Pharo. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-pharo-focused-sprint-bern-feb-26-td3251860.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stephan and Diego participated in &lt;a href=&quot;http:&#x2F;&#x2F;eindhoven.startupweekend.org&#x2F;&quot;&gt;Eindhoven startup weekend&lt;&#x2F;a&gt;. They got the innovation price. I could not find more information on the event website :&#x2F; &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Startup-weekend-success-td3328004.html&quot;&gt;full thread&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Releases&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;New release of &lt;a href=&quot;http:&#x2F;&#x2F;www.ofset.org&#x2F;drgeo&quot;&gt;Dr Geo II: 11.03&lt;&#x2F;a&gt;. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-Dr-Geo-II-release-11-03-for-Linux-Mac-Windows-td3335915.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Olivier released a &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;LDAPlayer&#x2F;&quot;&gt;LDAP package&lt;&#x2F;a&gt; and a &lt;a href=&quot;http:&#x2F;&#x2F;www.auverlot.fr&#x2F;index.php?z=21&quot;&gt;tutorial&lt;&#x2F;a&gt;. It is known to work on Pharo 1.2rc. full threads &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;LDAPlayer-td3333079.html&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a&gt;there&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Pharo 1.2 should be released. The infrastructure should be improved. At the moment time is lost in Metacello configurations for external packages. Stef reminds us this fact and want to see 1.2 final soon. One solution pushed by Doru would be to set a hard deadline one month before the release. Packages that do not work are removed from the distributon. Laurent pointed that the Linux process could also be a goot candidate. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;About-1-2-td3326052.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Alexandre reminds us about the existence of &lt;a href=&quot;http:&#x2F;&#x2F;www.silversmalltalk.com&#x2F;&quot;&gt;SilverSmalltalk&lt;&#x2F;a&gt;. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;SilverSmalltalk-td3323486.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Users&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;More information about Squeaksource 3 on a thread. Nobody have heard about it before. As we have seen last week, the future looks promising. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-Sources-Google-Hit-Ratio-td3318289.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;There are some discussions about the state of &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Croquet_Project&quot;&gt;OpenCroquet&lt;&#x2F;a&gt; (now known as &lt;a href=&quot;http:&#x2F;&#x2F;www.opencobalt.org&#x2F;&quot;&gt;OpenCobalt&lt;&#x2F;a&gt;). (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;OpenCroquet-Website-td3319189.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Good thread on TDD. &lt;em&gt;How many time should spend on tests?&lt;&#x2F;em&gt;. Laurent gave a nice reference to &lt;a href=&quot;http:&#x2F;&#x2F;www.amazon.com&#x2F;Test-Driven-Development-Practical-David-Astels&#x2F;dp&#x2F;0131016490&quot;&gt;Dave Astels book&lt;&#x2F;a&gt;. If you dont know TDD or find it difficult to apply in practice, read the &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Good-reference-on-time-on-unit-testing-td3326543.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Good question from Edouard. He pointed a stupid method: &lt;em&gt;2 days&lt;&#x2F;em&gt; vs. &lt;em&gt;2 day&lt;&#x2F;em&gt;. The latter evaluates to the duration of 1 day. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;2-days-vs-2-day-td3325706.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Dennis asked if it is possible to use russian fonts with the CogVM. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Is-it-possible-to-setup-Russian-fonts-in-Pharo-Cog-VM-td3329185.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;nullPointer experiences a &lt;strong&gt;very&lt;&#x2F;strong&gt; slow package loading on Windows. Mariano reminds that &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;documentation&#x2F;faq&quot;&gt;antivirus could be the root of the problem&lt;&#x2F;a&gt;. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Great-slowness-for-install-CLFramework-td3327888.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Alexandre asked what &lt;a href=&quot;&quot;&gt;Coral&lt;&#x2F;a&gt; is about. Documentation is lacking but according the authors it should work. The &lt;a href=&quot;http:&#x2F;&#x2F;www.auverlot.fr&#x2F;pharo&#x2F;coralinstall&#x2F;&quot;&gt;only tutorial&lt;&#x2F;a&gt; you will find about it is written in french and does not go very deep. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Coral-td3335190.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef explained to Miguel how to get a diff between to versions on Monticello. It is the kind of thing you will obviously need one day. Bookmark this post ;) &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Monticello-diff-between-2-version-td3336953.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Laurent discovered that SSL is not supported on Pharo out of the box. Sven mentioned &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;SqueakSSL.html&quot;&gt;SqueakSSL&lt;&#x2F;a&gt; but it does not seem to work on Pharo (MacOS and Linux seem problematic as well). Esteban proposed to use &lt;a href=&quot;http:&#x2F;&#x2F;www.stunnel.org&#x2F;&quot;&gt;stunnel&lt;&#x2F;a&gt; to create an SSL tunneling proxy. Not very elegant and straightforward but it works. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Url-HTTPSocket-with-https-td3331103.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Olivier asked if there are any documents on how to create GUIs in Pharo. &lt;a href=&quot;http:&#x2F;&#x2F;www.pharocasts.com&#x2F;&quot;&gt;Pharocasts&lt;&#x2F;a&gt; were mentioned and Bill explained briefly the born of Morphic and Polymorph. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;GUI-td3333102.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef struggled to load &lt;a href=&quot;http:&#x2F;&#x2F;www.lukas-renggli.ch&#x2F;smalltalk&#x2F;magritte&quot;&gt;Magritte&lt;&#x2F;a&gt; without &lt;a href=&quot;http:&#x2F;&#x2F;seaside.st&#x2F;&quot;&gt;Seaside&lt;&#x2F;a&gt;. He gave the snippet:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Gofer it
&lt;&#x2F;span&gt;&lt;span&gt;  renggli: &amp;#39;magritte2&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  package: &amp;#39;ConfigurationOfMagritte2&amp;#39;;
&lt;&#x2F;span&gt;&lt;span&gt;  load.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(ConfigurationOfMagritte2 project version: &amp;#39;2.0.6&amp;#39;) load: #(&amp;#39;Core&amp;#39;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Internal and discussions&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dale did a &lt;em&gt;solo sprint&lt;&#x2F;em&gt; to fix the failing tests in Metacello and released a new version. full threads &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Metacello-Configuration-Pharo1-2-solo-sprint-Portland-Oregon-Saturday-and-Sunday-td3325475.html&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Fwd-Metacello-Metacello-1-0-beta-28-3-1-released-td3325601.html&quot;&gt;there&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef introduced RPackage, a rewrite of PackageInfo. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;introducing-RPackage-td3326084.html&quot;&gt;full thread&lt;&#x2F;a&gt;. More discussion about it in this &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;About-RPackage-td3330650.html&quot;&gt;other thread&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef continues his war against uncommented classes. It is sometimes &lt;strong&gt;very&lt;&#x2F;strong&gt; difficult to use a class&#x2F;package&#x2F;framework when you do not know where to start. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;comments-comments-comments-again-td3326862.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Discussion about &lt;a href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;articles&#x2F;azul_gc_in_detail&quot;&gt;the Azul Pauseless garbage collector&lt;&#x2F;a&gt;. If you are into the VM things, you could be interested with how it compare with the VisualWorks garbge collector. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Azul-Pauseless-GC-td3326066.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Marcus have some news from the Hudson front. They now have a Mac (so mac VMs will probably soon get the benefits of the continuous integration server). The Cog Unix VMs are also continuously built. And there is a new build for Project Sista. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Hudson-News-td3327917.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Eliot wrote a &lt;a href=&quot;http:&#x2F;&#x2F;www.mirandabanda.org&#x2F;cogblog&#x2F;2011&#x2F;03&#x2F;01&#x2F;build-me-a-jit-as-fast-as-you-can&#x2F;&quot;&gt;blog post&lt;&#x2F;a&gt; about JIT. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;another-blog-post-td3331940.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef warned the community about &lt;em&gt;XXX&lt;&#x2F;em&gt;. He seems to approach people with (crazy) business plans. He sent proposals to VCs where he mentioned virtual key team members who are in fact not related with him. German did not have bad experience with &lt;em&gt;XXX&lt;&#x2F;em&gt;. Anyway, be careful if you&amp;rsquo;re approached by a suspicious VC.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Pavel opened a &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=3782&quot;&gt;ticket&lt;&#x2F;a&gt; to get pangrams for various language. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;pangrams-td3334971.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Hilaire wants to get Locale works with a CogVM (to use it with the underpowered XO laptop). If you want to play with GDB and to dig into the VM the thread should interest you. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;COG-VM-and-Locale-td3331775.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.squeakdbx.org&#x2F;&quot;&gt;SqueakDBX&lt;&#x2F;a&gt; will get slots for &lt;a href=&quot;http:&#x2F;&#x2F;esug.org&#x2F;wiki&#x2F;pier&#x2F;Promotion&#x2F;SummerTalk&quot;&gt;SummerTalk&lt;&#x2F;a&gt;. Three mentors, three students. Very good news for this project. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-ESUG-supports-once-again-SqueakDBX-td3334864.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;The state of Smalltalk on tablets and mobile in &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Squeak-Pharo-Cuis-on-Android-td3333463.html&quot;&gt;this thread&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Benjamin announced that he (with Igor) managed to get a new Smalltalk kernel based on Pharo which is 2.2Mb and includes 230 classes. Impressive. This is very important to reach one the Pharo&amp;rsquo;s goal: have a minimal kernel from which needed packages are loaded. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Kernel-td3335157.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As usual, a lots of bugs were fixed and technical details were discussed both in the mailing list and in the &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;list&quot;&gt;bug tracking system&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo mailing list weekly summary #3</title>
		<published>2011-02-24T12:02:24+00:00</published>
		<updated>2011-02-24T12:02:24+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-02-24-pharo-mailing-list-weekly-summary-3-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-02-24-pharo-mailing-list-weekly-summary-3-html/</id>
		<content type="html">&lt;p&gt;End of week, time for the weekly Pharo digest. Following Ken Brown&amp;rsquo;s suggestion, I&amp;rsquo;ve renamed it &lt;em&gt;weekly summary&lt;&#x2F;em&gt; to avoid the confusion with the digest you automatically get from mailing list servers.&lt;&#x2F;p&gt;
&lt;p&gt;As I was on holidays, the summary will be short this week. If I missed something really important, let me know, I&amp;rsquo;ll edit this post.&lt;&#x2F;p&gt;
&lt;h2&gt;Events&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-pharo-focused-sprint-bern-feb-26-td3251860.html&quot;&gt;Pharo sprint organised&lt;&#x2F;a&gt; in Bern this Saturday (26th October). The taks of the day is to discuss and improve the Pharo IDE. Anyone can join (Smalltalk newcomers are welcome).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Announces&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.moosetechnology.org&#x2F;&quot;&gt;Moose&lt;&#x2F;a&gt; is available in version 4.3. Moose is a platform for software and data analysis. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-Moose-4-3-td3316625.html&quot;&gt;the announcement&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Miguel updated the configuration of OSProcess. The confifuration takes the &lt;a href=&quot;http:&#x2F;&#x2F;gemstonesoup.wordpress.com&#x2F;2011&#x2F;01&#x2F;17&#x2F;metacello-1-0-beta-28-unearthed&#x2F;&quot;&gt;symbolic versions&lt;&#x2F;a&gt; into account. OSProcess provides access to operating system functions (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-ConfigurationOfOSProcess-with-symbolic-versions-td3313985.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Benjamin wrote a Messenger application to run inside Pharo. Hopefully that could help the developers to communicate when working on Pharo. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Community-in-the-IDE-td2543540.html&quot;&gt;full thread&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Laurent wrote a simple &lt;a href=&quot;http:&#x2F;&#x2F;magaloma.blogspot.com&#x2F;2011&#x2F;02&#x2F;xml-browser-with-pharo.html&quot;&gt;XML browser&lt;&#x2F;a&gt;. Very handy ! (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;XML-browser-td3320622.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Alexandre announced &lt;a href=&quot;http:&#x2F;&#x2F;metacellobrowser.dcc.uchile.cl&#x2F;&quot;&gt;MetacelloBrowser&lt;&#x2F;a&gt;. This tool seems to be the best friend of Metacello. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;MetacelloBrowser-td3321023.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;User&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adrien asked how to load OmniBrowser in PharoCore 1.3. Guillermo gave the magic command ;) (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;OmniBrowser-in-PharoCore-1-3-td3317323.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Hilaire asked how to change the default font size (he is working on the XO laptop). It is always the kind of tips you eventually need. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;StandardFonts-defautFont-td3317772.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;He also got some problems with the Cog VM and the locale plugin. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;COG-and-locale-td3318081.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef asked how people reify XML and objects. Using XMLParser is always the same the same boring work. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pattern-for-reifying-XML-doc-td3319260.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Olivier asked how to change the Pharo logo in the IDE. This is also the kind of simple question that you will probably ask one day. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Replacing-the-pharo-logo-td3322504.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Pharo&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Mariano is back after 25 days of holidays without internet. I guess I&amp;rsquo;ll have much more work for my weekly summaries now ;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef continues to comment FileSystem and asked the opinion of the community on some point. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Need-your-point-of-view-on-FSPath-and-others-td3313975.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;The virtual sprint for Pharo 1.2 was a bit hard to organise because of timezones (&lt;a href=&quot;http:&#x2F;&#x2F;www.doodle.com&#x2F;byvynpkmm87hc3x8&quot;&gt;doodle&lt;&#x2F;a&gt;). I have no idea if it was successful though.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;squeaksource.com&quot;&gt;Squeaksource&lt;&#x2F;a&gt; is down more and more often these days. As usual, people talked about possible replacements. There will be at least one alternative (Esteban has something, The Iliad guys and Esug are working and I&amp;rsquo;ve heard about a possible Squeaksource 3). Read the (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;SqueakSource-down-again-td3317484.html&quot;&gt;full thread&lt;&#x2F;a&gt;) if you&amp;rsquo;re interested. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-Sources-Google-Hit-Ratio-td3318289.html&quot;&gt;Another thread&lt;&#x2F;a&gt; can also be a good read in you are in the version control thing. With the success of &lt;a href=&quot;http:&#x2F;&#x2F;github.com&quot;&gt;Github&lt;&#x2F;a&gt;, it is crucial from a community perspective to have a nice place to host our beloved source code.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Another consulting company &lt;a href=&quot;http:&#x2F;&#x2F;www.channelregister.co.uk&#x2F;2011&#x2F;02&#x2F;20&#x2F;cobol_is_the_new_language_to_know&#x2F;&quot;&gt;said&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote class=&quot;posterous_short_quote&quot;&gt;&lt;p&gt;Smalltalk or FoxPro should be junked or moved to a new system immediately as
a result of non-support and no further development of the environments.&lt;&#x2F;p&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;You can imagine the reactions in the mailing list ;) &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Cobol-is-the-new-language-to-know-td3317188.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;State of Magma in Pharo by Miguel. Magma is an object-oriented database. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Is-repository-down-for-Magma-td3321104.html&quot;&gt;thread&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thanks for reading !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pharo mailing list weekly digest #2</title>
		<published>2011-02-18T08:09:00+00:00</published>
		<updated>2011-02-18T08:09:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-02-18-pharo-mailing-list-weekly-digest-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-02-18-pharo-mailing-list-weekly-digest-html/</id>
		<content type="html">&lt;p&gt;End of the week, time for the Pharo weekly digest. This week was quite busy on the mailing list, if I overlooked something important, please comment this post.&lt;&#x2F;p&gt;
&lt;p&gt;At some point, this digest will probably be hosted on the main &lt;a href=&quot;http:&#x2F;&#x2F;www.pharo-project.org&#x2F;&quot;&gt;Pharo website&lt;&#x2F;a&gt;. If you want to help, you are more welcome !&lt;&#x2F;p&gt;
&lt;p&gt;I&amp;rsquo;ll be absent until Wednesday (Italy!), so I&amp;rsquo;ll probably miss some threads for the next digest :&#x2F;&lt;&#x2F;p&gt;
&lt;h2&gt;Pharo promotion&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Pharo board calls for Pharo support in the industry. It wants to create a legal infrastructure to collect funds to perform engineering tasks. The end goal is to streghten Pharo. The consortium is not limited to research groups and companies; individuals are welcome! If you are interested in Pharo, download the letter, sign it and send it back. It is &lt;strong&gt;crucial&lt;&#x2F;strong&gt; to get a stronger open source Smalltalk. Beware that there are two versions of the letter, be sure to get the latest one. &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Call-for-Pharo-Support-important-td3306729.html&quot;&gt;See the thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stef created a &lt;a href=&quot;http:&#x2F;&#x2F;www.linkedin.com&#x2F;e&#x2F;hzbhb7-gkawp6l9-36&#x2F;vgh&#x2F;2558378&#x2F;&quot;&gt;LinkedIn group&lt;&#x2F;a&gt; for Pharo. It is quite successful (76 members so far).&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Events&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Laurent proposed to do some virtual sprint next week from monday to wednesday (evening &amp;ndash; France timezone). Check &lt;a href=&quot;http:&#x2F;&#x2F;www.doodle.com&#x2F;byvynpkmm87hc3x8&quot;&gt;the Doodle&lt;&#x2F;a&gt; if you want to join. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-1-2-virtual-sprint-td3305846.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2&gt;Misc&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Discussion about &lt;a href=&quot;https:&#x2F;&#x2F;www.hpi.uni-potsdam.de&#x2F;hirschfeld&#x2F;trac&#x2F;SqueakCommunityProjects&#x2F;wiki&#x2F;designer&quot;&gt;the new GUI visual designer&lt;&#x2F;a&gt; developed in HPI. This GUI designer targets Squeak but could be porter to Pharo. If I understood correctly, the authors use &lt;a href=&quot;https:&#x2F;&#x2F;www.hpi.uni-potsdam.de&#x2F;hirschfeld&#x2F;trac&#x2F;SqueakCommunityProjects&#x2F;wiki&#x2F;signals&quot;&gt;Signal&lt;&#x2F;a&gt; while Pharo has an explicit preference for &lt;a href=&quot;http:&#x2F;&#x2F;book.pharo-project.org&#x2F;book&#x2F;announcements&#x2F;&quot;&gt;Announcements&lt;&#x2F;a&gt;. The discussion moved to the old debate about GUI construction (should we use something like XML to describe a user interface ?), on the topic of how to integrate a big framework into Pharo and how to serialize smalltalk code. If you have followed the thread and if I missed something, please comment ! (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;A-new-GUI-visual-designer-td3067111.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;There was a doubt that the introduction of the Hudson build server was putting too much stress on Squeaksource (which is clearly unstable). Stéphane mentions a &lt;em&gt;new cool server&lt;&#x2F;em&gt;. I once heard about a SqueakSource-like project written in &lt;a href=&quot;http:&#x2F;&#x2F;www.iliadproject.org&#x2F;&quot;&gt;iliad&lt;&#x2F;a&gt; and running on top of (GNU Smalltalk)[&lt;a href=&quot;http:&#x2F;&#x2F;smalltalk.gnu.org&#x2F;&quot;&gt;http:&#x2F;&#x2F;smalltalk.gnu.org&#x2F;&lt;&#x2F;a&gt;]. Is there a correlation ? (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Hudson-and-Squeaksource-statistics-td3301186.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Janko announces a new version of Aida: Aida&#x2F;web 6.2 Spring edition is out. Aida is a web framework written in Smalltalk. Janko uses it in production for years now. It is good to see that things are also moving outside the Seaside sphere. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;ANN-Aida-Web-6-2-Spring-edition-is-out-td3301723.html&quot;&gt;full thread&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;A recurring question on the Seaside mailing-list is how to make a multilanguage (I18n) application in Seaside (or Smalltalk in general). Sebastian wrote a &lt;a href=&quot;http:&#x2F;&#x2F;blog.flowingconcept.com&#x2F;brandIt&#x2F;multiligual-web-applications-design-ala-smalltalk&quot;&gt;blog post&lt;&#x2F;a&gt; some time ago to explain his approach. There is a &lt;a href=&quot;http:&#x2F;&#x2F;book.pharo-project.org&#x2F;book&#x2F;Localisation&quot;&gt;dedicated chapter in the collaborative Pharo book&lt;&#x2F;a&gt; as well. If I remember well, some others do not follow the same approach. Please comment if you do.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=3699&quot;&gt;A very important issue&lt;&#x2F;a&gt; was reported and closed.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Two new success story were added on the website: a workflow platform called &lt;em&gt;Issys Tracking&lt;&#x2F;em&gt; and &lt;em&gt;DrGeo&lt;&#x2F;em&gt;, a scriptable tool used to teach geometry and mathematics in high school. More info on the &lt;a href=&quot;http:&#x2F;&#x2F;pharo-project.org&#x2F;about&#x2F;success-stories&quot;&gt;Pharo Website&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;The Cog Unix VM is now built with Hudson. The &lt;a href=&quot;http:&#x2F;&#x2F;rmod.lille.inria.fr&#x2F;web&#x2F;&quot;&gt;RMoD Team&lt;&#x2F;a&gt; in Lille will soon get a Mac Mini to build the Mac VMs. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Hudson-Cog-Unix-build-td3302938.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;A good reminder of how to call an external executable from an image. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Call-a-external-executable-file-What-is-the-best-option-td3303894.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Dale explained how to load the latest Seaside in Pharo 1.2. Very nice and clear post. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Loading-Seaside-into-Pharo-1-2-core-td3305778.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=3609&quot;&gt;RPackage&lt;&#x2F;a&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;pharo-ic.lille.inria.fr&#x2F;hudson&#x2F;view&#x2F;Pharo-TaskForces&#x2F;job&#x2F;Pharo%20RPackage%20All%20Tests&#x2F;&quot;&gt;now built&lt;&#x2F;a&gt; on the Hudson server. According to &lt;a href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;pharo&#x2F;issues&#x2F;detail?id=3609&quot;&gt;ticket 3609&lt;&#x2F;a&gt;, RPackage wants to replace PackageInfo.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Awesome news from the &lt;a href=&quot;http:&#x2F;&#x2F;blog.doit.st&#x2F;&quot;&gt;Cloudfork&lt;&#x2F;a&gt; project: OpenID and OAuth support in Smalltalk. More info on a &lt;a href=&quot;http:&#x2F;&#x2F;blog.doit.st&#x2F;2011&#x2F;02&#x2F;15&#x2F;cloudforksso-openid-and-oauth-support-for-smalltalk&#x2F;&quot;&gt;dedicated blog post&lt;&#x2F;a&gt;. This project will help &lt;strong&gt;a lot&lt;&#x2F;strong&gt; when it comes to integrate external APIs.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;The state of WeakAnnouncements was discussed in &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Working-with-weak-announcements-td3305802.html&quot;&gt;this thread&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;em&gt;Huge&lt;&#x2F;em&gt;¨&lt;&#x2F;em&gt; thread &lt;em&gt;could we agree to remove caseOf: and   caseOf:otherwise:&lt;&#x2F;em&gt;. I reckon that I didn&amp;rsquo;t follow the whole stuff but the conversation seems interesting for those enlightened enough to understand. The discussion covers the new compiler &lt;em&gt;Opal&lt;&#x2F;em&gt;. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;could-we-agree-to-remove-caseOf-and-caseOf-otherwise-td3302475.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Olivier tries to use the &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;LDAPlayer.html&quot;&gt;LDAPlayer&lt;&#x2F;a&gt; in Pharo. He needs to send requests to an LDAP server for a Seaside application. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Pharo-amp-LDAP-td3308841.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;German gave us a state of the &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;XMLRPC.html&quot;&gt;XMLRPC Project&lt;&#x2F;a&gt; which is funded by &lt;a href=&quot;http:&#x2F;&#x2F;esug.org&quot;&gt;ESUG&lt;&#x2F;a&gt;. He will focus on Pharo 1.1.1 and 1.2. It is broken in Squeak 4.2 at the momend.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Levente &lt;a href=&quot;http:&#x2F;&#x2F;lists.squeakfoundation.org&#x2F;pipermail&#x2F;vm-dev&#x2F;2011-February&#x2F;006886.html&quot;&gt;proposed a fix&lt;&#x2F;a&gt; for the UUID plugin problem. That will surely cures the headaches of some people.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Nicolas pointed some stuff in the String API and possible replacements to make it more smalltalkish. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Smalltalk-string-API-td3308431.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;HwaJong Oh works on a &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Collada&quot;&gt;COLLADA&lt;&#x2F;a&gt; file parser and wants to render it with &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;AlienOpenGL.html&quot;&gt;AlienOpenGL&lt;&#x2F;a&gt;. Fernando said that he has stopped to maintain the AlienOpenGL package but that it should be complete and stable enough to perform the task (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Render-a-COLLADA-mesh-with-OpenGL-td3308632.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Guillermo updates us about the state of Pharo 1.2. Hopefully we&amp;rsquo;ll see the official release quite soon ;) (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;1-2-Dev-Status-td3312363.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Fernando likes the PragmaMenuBuilder. You should look at it if you haven&amp;rsquo;t yet. The discussion moved to the local and global searches for pragmas. (&lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Menu-creation-and-invocation-td3311552.html&quot;&gt;full thread&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;See you next week !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>This week in the Pharo-Project mailing list</title>
		<published>2011-02-11T13:47:00+00:00</published>
		<updated>2011-02-11T13:47:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-02-11-this-week-in-the-pharo-project-mailing-list-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-02-11-this-week-in-the-pharo-project-mailing-list-html/</id>
		<content type="html">&lt;p&gt;In the following weeks, I will try to provide a weekly digest of the activity going in the pharo-developer mailing list (and sometimes some bits from the Seaside mailing list).&lt;&#x2F;p&gt;
&lt;p&gt;This digest will be biased by my own priorities and usage of Pharo. There are chances that &lt;em&gt;the commit you are waiting for ages that fix this broken hidden property in Pharo&lt;&#x2F;em&gt; will not be part of my digest. Do not hesitate to comment if I forgot something important.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Laurent launched a new game last week: &lt;strong&gt;Comment of the Day Contest&lt;&#x2F;strong&gt;. The principle is simple: every day a class without comment is randomly chosen. Mailing list participants propose a comment and at the end of the day, the best comment is integrated. It has generated some nice discussions so far.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;ci.pharo-project.org&quot;&gt;The Hudson server&lt;&#x2F;a&gt; now builds a Seaside and runs all the tests in the Pharo 1.2 build. Continuous integration is definitely the big new thing in the Pharo community.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Esteban wrote a new article about the &lt;a href=&quot;http:&#x2F;&#x2F;smallworks.com.ar&#x2F;en&#x2F;community&#x2F;Reef&#x2F;&quot;&gt;Reef framework&lt;&#x2F;a&gt;. Simply put, Reef is a framework on top of Seaside that let you build dynamic components.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Joachim announced the release of &lt;a href=&quot;http:&#x2F;&#x2F;jniport.wikispaces.com&#x2F;&quot;&gt;JNIPort 2.0&lt;&#x2F;a&gt;. This library allows you invoke Java code from Smalltalk. The big change of this version is the port to Squeak&#x2F;Pharo (previous versions were only running with VisualWorks).&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Tony &lt;a href=&quot;http:&#x2F;&#x2F;www.tonyfleig.com&#x2F;smallthoughts&#x2F;blog&#x2F;tffiler&quot;&gt;published&lt;&#x2F;a&gt; a great tool to manage external files with Monticello. When writing web applications you often have javascript&#x2F;CSS&#x2F;png files hanging around. It can be a mess to deal with Monticello on one side and Git&#x2F;SVN on the other. &lt;a href=&quot;http:&#x2F;&#x2F;www.squeaksource.com&#x2F;TFFiler&quot;&gt;TFFiler&lt;&#x2F;a&gt; puts everything into Monticello. Very handy.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;New COG VMs are available: &lt;a href=&quot;http:&#x2F;&#x2F;www.mirandabanda.org&#x2F;files&#x2F;Cog&#x2F;VM&#x2F;VM.r2359&#x2F;&quot;&gt;SimpleStackBasedCogit&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;www.mirandabanda.org&#x2F;files&#x2F;Cog&#x2F;VM&#x2F;VM.r2361&quot;&gt;StackToRegisterMappingCogit&lt;&#x2F;a&gt;. The latter one is faster but SimpleStackBasedCogit still exists just in case people find bugs with the StackToRegisterMappingCogit that are not in SimpleStackBasedCogit. SimpleStackBasedCogit is &amp;ldquo;mature&amp;rdquo;. See the &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;new-Cog-VMs-available-td3263525.html&quot;&gt;whole thread&lt;&#x2F;a&gt; for more technical details. Those VMs are no longer one-way street. With previous releases, once you had saved an image with a Cog VM you could not open it in a regular VM anymore. This is no longer the case.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Guillermo &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;copying-all-versions-to-squeaksource-td3263732.html&quot;&gt;shared a nice trick&lt;&#x2F;a&gt; to push and load all versions to&#x2F;from Squeaksource with &lt;a href=&quot;http:&#x2F;&#x2F;www.lukas-renggli.ch&#x2F;blog&#x2F;gofer&quot;&gt;Gofer&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Oscar posted a link to a &lt;a href=&quot;https:&#x2F;&#x2F;gforge.inria.fr&#x2F;frs&#x2F;download.php&#x2F;28243&#x2F;Settings.pdf&quot;&gt;draft chapter about the Settings Framework&lt;&#x2F;a&gt;. It will be included in  &lt;a href=&quot;http:&#x2F;&#x2F;pharobyexample.org&#x2F;&quot;&gt;&lt;em&gt;Pharo By Example 2&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;. Comments are welcome.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;There was a discussion about syntax highlighting for Smalltalk code in HTML pages. Laurent uses &lt;a href=&quot;http:&#x2F;&#x2F;softwaremaniacs.org&#x2F;soft&#x2F;highlight&#x2F;en&#x2F;&quot;&gt;highlight.js&lt;&#x2F;a&gt; on the PharoCast website, Max Leske wrote a &lt;a href=&quot;http:&#x2F;&#x2F;buildinggitfs.blogspot.com&#x2F;2010&#x2F;04&#x2F;smalltalk-brush-for-syntax-highlighter.html&quot;&gt;a brush for Syntaxhighlighter&lt;&#x2F;a&gt; and Nick pointed that &lt;a href=&quot;http:&#x2F;&#x2F;pygments.org&#x2F;&quot;&gt;Pygments&lt;&#x2F;a&gt; supports Smalltalk syntax.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stephane announced that the talk of the &lt;a href=&quot;http:&#x2F;&#x2F;www.inria.fr&#x2F;centre-de-recherche-inria&#x2F;lille-nord-europe&#x2F;agenda&#x2F;smalltalk&quot;&gt;Deep into Smalltalk school&lt;&#x2F;a&gt; will probably be recorded. &lt;em&gt;Deep into Smalltalk&lt;&#x2F;em&gt; is five days of lectures about advanced Smalltalk topics given by a great selection of speaker. Make sure you attend if you&amp;rsquo;re interested by VMs, sockets, FFI or C-Smalltalk interactions.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Stephane decided to bring FileSystem into Pharo for real and posted a roadmap of what would be cool to have this package.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;PharoConf in Annecy. Lots of tickets were processed. Congrats !&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;p&gt;Marcus &lt;a href=&quot;http:&#x2F;&#x2F;forum.world.st&#x2F;Hudson-updates-td3300535.html&quot;&gt;gave the state&lt;&#x2F;a&gt; of the Hudson build server for Pharo and related project.&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course, there were &lt;strong&gt;a lot&lt;&#x2F;strong&gt; of bug fixes and improvements.&lt;&#x2F;p&gt;
&lt;p&gt;See you next week !&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Javascript, The Good Parts</title>
		<published>2011-01-11T13:08:00+00:00</published>
		<updated>2011-01-11T13:08:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2011-01-11-javascript-the-good-parts-tags-javascript-boo-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2011-01-11-javascript-the-good-parts-tags-javascript-boo-html/</id>
		<content type="html">&lt;p&gt;I&#x27;ve just finished to read &lt;a href=&quot;http:&#x2F;&#x2F;oreilly.com&#x2F;catalog&#x2F;9780596517748&quot;&gt;Javascript: The Good
Parts&lt;&#x2F;a&gt; of &lt;a href=&quot;http:&#x2F;&#x2F;www.crockford.com&#x2F;&quot;&gt;Douglas
Crockford&lt;&#x2F;a&gt;. If you&amp;rsquo;re doing Javascript
development you should read it if you haven&amp;rsquo;t.&lt;&#x2F;p&gt;
&lt;p&gt;This book is not a definitive guide to Javascript but will show you
which part of the language to avoid if you want to eliminate a whole
class of problems.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some striking (at least for me) examples:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-js &quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span&gt;&amp;#39;&amp;#39; == &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; false
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;== &amp;#39;&amp;#39;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; true
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;== &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&amp;rsquo;s because == tries to coerce the values if they are of different types.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;return
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  status: true
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Will not return an object with a `status` field. It will return
`undefined`. Do you know why?&lt;&#x2F;p&gt;
&lt;p&gt;Another nice one is the `parseInt()` function.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;parseInt(&amp;#39;07&amp;#39;) &#x2F;&#x2F; returns 7
&lt;&#x2F;span&gt;&lt;span&gt;parseInt(&amp;#39;08&amp;#39;) &#x2F;&#x2F; returns 0
&lt;&#x2F;span&gt;&lt;span&gt;parseInt(&amp;#39;09&amp;#39;) &#x2F;&#x2F; returns 0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&amp;rsquo;s because when the first character of the parsed string is a zero,
it is evaluated in base 8. Seriously. In javascript. A high level
language. Wow.&lt;&#x2F;p&gt;
&lt;p&gt;Don&amp;rsquo;t worry, the book is not only a compilation of the weird design
choices of Javascript. It will guide you through a world without global
variables and will show you how to use functions to create modules. You
will learn to master the prototypal object model and understand why the
`new` construct in Javascript is evil.&lt;&#x2F;p&gt;
&lt;p&gt;Highly recommended.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>HEMA Packaging &amp; Design</title>
		<published>2010-12-07T11:11:00+00:00</published>
		<updated>2010-12-07T11:11:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-12-07-hema-packaging-design-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-12-07-hema-packaging-design-html/</id>
		<content type="html">&lt;p&gt;I&#x27;ve always liked HEMA shops. They basically all you need for everyday life.
From candies, to socks through contact lenses, you always find what you need.
Many of those goods and their packaging are greatly designed. I recently bought
an economical light bulb. The packaging is great.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2010&#x2F;12&#x2F;18380096-lightbulb-hema.jpg&quot; alt=&quot;HEMA lightbulbs package&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Check how informations are displayed. The socket size (E27) is on the socket.
The luminosity on the light bulb. Simple and beautiful. No plastic. Now compare
it with that.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2010&#x2F;12&#x2F;18380243-philips.jpg&quot; alt=&quot;Philips packaging&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;HEMA has a great sense of functional design. Unfortunately, not all their
products get the same love. Here is for example halogen lightbulb (no, I don&#x27;t
own a lightbulbs collection) package.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2010&#x2F;12&#x2F;18380099-lightbulb3.jpg&quot; alt=&quot;halogen HEMA bulbs&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sorry, it is open but I needed some light to shave this morning. The package is
simple but it looks like any other brand. And it has unnecessary plastic. Their
products reminds me an other line of products from &lt;a
href=&quot;http:&#x2F;&#x2F;www.actulogo.fr&#x2F;2010&#x2F;11&#x2F;mdr-la-mdd&#x2F;&quot;&gt;Monoprix&lt;&#x2F;a&gt;. The packagings
were full of puns about the product.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m quite receptive to this kind of attention from the makers of the products I
buy. Are you ?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The ubiquitous Bancontact</title>
		<published>2010-11-01T02:44:00+00:00</published>
		<updated>2010-11-01T02:44:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-11-01-bancontact-mistercash-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-11-01-bancontact-mistercash-html/</id>
		<content type="html">&lt;p&gt;I strongly believe that one day we will ge the &lt;em&gt;zero-note wallet&lt;&#x2F;em&gt;. Your debit card (or your phone, or the &lt;a href=&quot;http:&#x2F;&#x2F;www.thecheers.org&#x2F;Tech&#x2F;article_734_Get-identified-under-your-skin.html&quot;&gt;RFID chip implanted in your arm&lt;&#x2F;a&gt;)&amp;nbsp; will take over notes and coins.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;div class=&#x27;p_embed p_image_embed&#x27;&gt;
&lt;img src=&#x27;&#x2F;images&#x2F;2010&#x2F;11&#x2F;16936339-Logo_Bancontact_Mister_Cash_tcm39-5406.jpg&#x27;&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;In Belgium, the main actor in the debit card market is Bancontact&#x2F;Mistercash. It is virtually anywhere. I had my croissant and coffee in &lt;a href=&quot;http:&#x2F;&#x2F;www.lepainquotidien.be&#x2F;&quot;&gt;Le Pain Quotidien&lt;&#x2F;a&gt; this morning and tried to pay with Bancontact. The lady told me that I could not pay if the order is less than10&amp;euro;. What ? How many persons have a +10&amp;euro; breakfast ?&lt;&#x2F;p&gt;
&lt;p&gt;I went to the local McDonalds to have another (much cheaper) coffee. Big sign on the cash machine &lt;em&gt;For your comfort and our safety, pay by debit card&lt;&#x2F;em&gt;. Ok. Fine. When I gave my card, the cashier showed me sign in his back. &lt;em&gt;No Bancontact under 10&amp;euro;&lt;&#x2F;em&gt;. Coffee is 1.75&amp;euro;. He let me pay by card but still.&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s wrong with Bancontact ? Are the fees per transaction so high that shops lose money when the transaction is less than 10&amp;euro; ? If they want to be ubiquitous why are putting such a high barrier ?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Design is more than pretty picture</title>
		<published>2010-07-06T01:58:00+00:00</published>
		<updated>2010-07-06T01:58:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-07-06-design-is-more-than-pretty-picture-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-07-06-design-is-more-than-pretty-picture-html/</id>
		<content type="html">&lt;div style=&quot;&quot;&gt;
&lt;strong style=&quot;display: block; margin: 12px 0 4px;&quot;&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.slideshare.net&#x2F;novaurora&#x2F;10-things-ceos-need-to-know-about-design&quot;&gt;10 Things CEOs Need to Know About Design &lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; 
&lt;object height=&quot;355&quot; width=&quot;425&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http:&#x2F;&#x2F;static.slidesharecdn.com&#x2F;swf&#x2F;ssplayer2.swf?doc=bessemertalk-100512183606-phpapp01&amp;amp;stripped_title=10-things-ceos-need-to-know-about-design&quot; &#x2F;&gt;
&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; &#x2F;&gt;
&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; &#x2F;&gt; &lt;embed src=&quot;http:&#x2F;&#x2F;static.slidesharecdn.com&#x2F;swf&#x2F;ssplayer2.swf?doc=bessemertalk-100512183606-phpapp01&amp;amp;stripped_title=10-things-ceos-need-to-know-about-design&quot; type=&quot;application&#x2F;x-shockwave-flash&quot; height=&quot;355&quot; width=&quot;425&quot;&gt;&lt;&#x2F;embed&gt;
&lt;&#x2F;object&gt;
&lt;&#x2F;div&gt;
&lt;blockquote&gt;
&lt;div style=&quot;padding: 5px 0 12px;&quot;&gt;Talk benefits, not features&lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;div style=&quot;padding: 5px 0 12px;&quot;&gt;Is my favorite quote of the presentation.&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Seaside WAAnchor fun</title>
		<published>2010-06-14T13:10:00+00:00</published>
		<updated>2010-06-14T13:10:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-06-14-seaside-waanchor-fun-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-06-14-seaside-waanchor-fun-html/</id>
		<content type="html">&lt;p&gt;I&amp;rsquo;m currently playing with &lt;a href=&quot;http:&#x2F;&#x2F;seaside.st&quot; title=&quot;Seaside website&quot;&gt;Seaside&lt;&#x2F;a&gt; (a Smalltalk web framework) for a pet project. As you maybe know, Seaside is, by default, not very friendly with URLs. I wanted to have bookmarkable URLs for user convenience and for search engine. Ramon Leon explains how he managed to get nice urls for his blog in a super-interesting &lt;a href=&quot;http:&#x2F;&#x2F;onsmalltalk.com&#x2F;clean-urls-in-seaside&quot;&gt;blog post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When playing with WAAnchor methods, I fought with a weird behaviour:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;html anchor
&lt;&#x2F;span&gt;&lt;span&gt;  callback: [self moveToPage: page];
&lt;&#x2F;span&gt;&lt;span&gt;  useBaseUrl;
&lt;&#x2F;span&gt;&lt;span&gt;  extraPath: page slug;
&lt;&#x2F;span&gt;&lt;span&gt;  with: page title.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;did not work, while&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;html anchor
&lt;&#x2F;span&gt;&lt;span&gt;  useBaseUrl;
&lt;&#x2F;span&gt;&lt;span&gt;  extraPath: page slug;
&lt;&#x2F;span&gt;&lt;span&gt;  callback: [self moveToPage: page];
&lt;&#x2F;span&gt;&lt;span&gt;  with: page title.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;worked fine. Can you see the difference in these two snippets?&lt;&#x2F;p&gt;
&lt;p&gt;The reason of the resulting bug is quite simple but is hard to spot when you&amp;rsquo;re not careful: the method `useBaseUrl` should always be the first to be called in a method cascade on a WAAnchor. Indeed, both `extraPath:` and `callback:` will affect the url of the WAAnchor while `useBaseUrl` will reset it. This reset will cancel all the operations you&amp;rsquo;ve done before on the url of the WAAnchor.&lt;&#x2F;p&gt;
&lt;p&gt;Moral of the story: beware of side effect (or How I Learned to Stop Worrying and Love Functional Programming)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Better, Faster, Stronger</title>
		<published>2010-04-02T07:17:14+00:00</published>
		<updated>2010-04-02T07:17:14+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-04-02-better-faster-stronger-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-04-02-better-faster-stronger-html/</id>
		<content type="html">&lt;p&gt;Web development is a quite hot topic for developers these days. Some think that the web is the future and that native apps are a relic of the past. I would not say that it is that simple (iPhone&#x2F;iPad apps anyone?) but it is clear that webapps work well for many tasks. &lt;p &#x2F;&gt; Some years ago frameworks started to appear in order to facilitate the development of web applications. They promise faster development time, more robust application and easy maintenance. We all know that a silver bullet does not exist in software development but it&#x27;s kinda funny to see what all those frameworks promise. Here are some excerpts from some website of them. &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.springsource.org&#x2F;&quot;&gt;Spring&lt;&#x2F;a&gt; (Java)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Spring delivers significant benefits for many projects, increasing development productivity and runtime performance while improving test coverage and application quality. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;cakephp.org&#x2F;&quot;&gt;CakePHP&lt;&#x2F;a&gt; (PHP)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;CakePHP enables PHP users at all levels to rapidly develop robust web applications. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.iliadproject.org&#x2F;&quot;&gt;iliad&lt;&#x2F;a&gt; (Smalltalk)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Iliad is a Smalltalk web application framework. It is designed to be simple and make web development as effective as possible. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.catalystframework.org&#x2F;&quot;&gt;Catalyst&lt;&#x2F;a&gt; (Perl)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Catalyst will make web development something you had never expected it to be: Fun, rewarding and quick. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.symfony-project.org&#x2F;&quot;&gt;Symfony&lt;&#x2F;a&gt; (PHP)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;It [Symfony] provides an architecture, components and tools for developers to build complex web applications faster. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;rubyonrails.org&#x2F;&quot;&gt;Ruby on Rails&lt;&#x2F;a&gt; (Ruby)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_medium_quote&quot;&gt; &lt;br &#x2F;&gt;Ruby on Rails is an open-source web framework that&#x27;s optimized for programmer happiness and sustainable productivity. It lets you write beatiful code by favoring convention over configuration. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt;  &lt;br &#x2F;&gt;&lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;pylonshq.com&#x2F;&quot;&gt;Pylons&lt;&#x2F;a&gt; (Python)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Pylons is a lightweight web framework &lt;br &#x2F;&gt;emphasizing flexibility and rapid development &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.djangoproject.com&#x2F;&quot;&gt;Django&lt;&#x2F;a&gt; (Python)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Django makes it easier to build better Web apps more quickly and with less code. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; &lt;h2&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.seaside.st&quot;&gt;Seaside&lt;&#x2F;a&gt; (Smalltalk)&lt;&#x2F;h2&gt;&lt;blockquote class=&quot;posterous_short_quote&quot;&gt; &lt;br &#x2F;&gt;Seaside provides a layered set of abstractions over HTTP and HTML that let you build highly interactive web applications quickly, reusably and maintainably. &lt;br &#x2F;&gt;&lt;&#x2F;blockquote&gt; &lt;p &#x2F;&gt; Wow with all those promises, you have no excuse to deliver crappy webapps. I like those headlines have no meaning at all. Do not trust someone who is pretending that everything will be easy with his tool&#x2F;framework. Except when the tool in question is Clojure or Smalltalk of course :)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>On API Consistency</title>
		<published>2010-03-20T03:03:00+00:00</published>
		<updated>2010-03-20T03:03:00+00:00</updated>
		<link href="https://tulipemoutarde.be/posts/2010-03-20-on-api-consistency-html/" type="text/html"/>
		<id>https://tulipemoutarde.be/posts/2010-03-20-on-api-consistency-html/</id>
		<content type="html">&lt;p&gt;Interacting with a well design API is a pleasure. When an interface is consistent and works in the way I expect it to work I feel good. Gregory T. Brown wrote an &lt;a href=&quot;http:&#x2F;&#x2F;blog.rubybestpractices.com&#x2F;posts&#x2F;gregory&#x2F;rbp-ch2-3.html&quot;&gt;excellent chapter&lt;&#x2F;a&gt; on this subject in his (now freely available) book &#x27;Ruby Best Practices&#x27;. &lt;p &#x2F;&gt; Something struck me in jQuery last week: map() and each()&#x27;s parameters. &lt;p &#x2F;&gt;  From &lt;a href=&quot;http:&#x2F;&#x2F;jqapi.com&#x2F;&quot;&gt;jQuery&#x27;s documentation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;.map( callback(index, domElement) ) .each( function(index, Element) ) jQuery.each( collection, callback(indexInArray, valueOfElement) ) jQuery.map( array, callback(elementOfArray, indexInArray) )
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;br &#x2F;&gt;Ok, what&#x27;s the deal? &lt;br &#x2F;&gt;Look at the parameters of the callback of jQuery.map(). The order is different than all the others. Why?&lt;p &#x2F;&gt; This kind of things drives me nuts.&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
