Category: Programming

Returning to Elixir/Phoenix

I still earn my living with Rails, but I’ve become a little cynical about running it for personal projects. This is mainly because there’s a minimum amount of resources you need to run a Rails app of any complexity and it’s a bit expensive for hobbyist things. For example, I run my own Mastodon instance and it feels expensive for one person. I could allow others to use the instance, but then I’d have to police them and nah. I like having my own instance, some dickhead can’t call a ban hammer down on me.

I tried the Phoenix platform a few years back, talking to a JS front end, and it wasn’t quite there yet. It’s much more mature now, and more than ready for prime time. There’s also the Live Page thing, so no need to scar myself mentally trying to use some over engineered madness like React. I can just write some HTML and embed a few things. This is also how I feel about Rails these days, with Turbo and a little judicious use of JS you can just add the frills you need without several megabytes of download and a very slow response time. (However, if you include the React compiler it makes a big difference).

The project

Some years ago I became a little obsessed with word games on my phone. The ones I got into took a longish word and then used it to construct other words. The simplest one just wants a list of the other words, usually in alphabetical order, the more complex one creates a crossword style layout so you can sometimes get letters from the words you’re trying to work out.

Now, the game makers want to make some money, and I don’t object to that. So they allow you to win in game tokens and spend them on hints if you get stuck. Then you can purchase tokens if you’ve not managed to win enough to get past where you’re stuck. One game fills up a piggy bank as you solve puzzles and they charge money to open the piggy bank, we’re talking £20 or £30 here. They also want to charge as much as £30 if you want to top them up without having to earn them through the game. I kept getting stuck and won’t pay more than £2 or £3 for things like this, £30 being a relatively serious amount of money if you’re parting with it every few days. I do object to that, if you look at paying for Angry Birds (for example, he said) you can build up quite a lot of spending there, but only is relatively small amounts. They have it about right, or at least they did a couple of years ago.

Enter the Werds Gem that I created to search through a list of British and US American English words from the tool Scowl and do some matching against the source word and the pattern you might be looking for. I must have been quite pissed off to put in that much effort. I got ambitious and thought I would front the Gem with a Rails app and maybe start a web site for fellow frustrated word game fans. I even failed an interview I never had when the programmers looked at it on github and didn’t like that it probably wouldn’t work well in a web environment so wouldn’t talk to me, despite the readme never claiming it was architected for that and anything other than a play time alpha software thing. It works fine in the console when you’re sat there in your jammies trying to solve a puzzle before you go to bed.

I did attempt a Rails app and even got something primitive going on Heroku, which is gone now, but the slowness of the search meant it was unreliable and would time out. The gem was a proof of concept, didn’t have any tests, the documentation wasn’t quite right, etm.. It scratched my frustration with the word game itch though, I didn’t play these games for a year or so because other things happened and the project went back to sleep.

I got back into them a few weeks ago and started using the gem when I was stuck. The thought of the website got me going too, but the problems with Rails I mentioned earlier made me think I’d go for something cheap and relatively easy to work with, so let’s make a web site with Phoenix and use the lovely Fly to deploy. I recommend Fly, by the way, cheap and reliable, developer focussed, and not wrecked by money grubbing like Heroku now is.

To go to Elixir I had to translate the gem to a Hex library and work out how to share the dictionary in that environment. I also embraced the Elixir approach of writing documentation strings, specs, and tests for your public functions. Asking Deep Think to translate parts of the gem into Elixir made me realise that the approach I took in Ruby land was rushed and flawed. I worked out what the Ruby code was doing, but it was obvious that it did things in a back to front way.

The Ruby code would construct a Regex to get a list of candidate words, and then apply another regex to whittle it down, then check that the letters in the source word weren’t used more than the amount of times they appear in the source word. The code was incredibly convoluted.

So, as a first pass I wanted to create a function that took the source word, any candidate mask for a word to search for, and create the regex for it.

def make_mask(source_word, match_string) do
pre_processed_match =
match_string
|> String.replace(@ellipsis, "...")
|> String.downcase()
|> String.replace(~r/[[:space:]]/, "")

used_chars =
pre_processed_match
|> String.replace(".", "")
|> String.graphemes()

adjusted_regex =
Enum.reduce(used_chars, source_word, fn char, acc ->
String.replace(acc, char, "", global: false)
end)

"^#{String.replace(pre_processed_match, ".", "[#{adjusted_regex}]")}$"
end

The pre_processed_match string cleans up the source word. We’re reusing the regex match that a . character matches anything, but in this case anything is a character from the source word. I’d had problems with earlier web app when three dots got changed into an ellipsis, so kept that in. Say we have a source word banana and the mask of “..ana”, the regex we want is /[ban][ban]ana/ to scan the main dictionary with.

Then used_chars becomes a string with all the characters that are in the candidate list, ignoring any dots. Then we adjust it so the first occurrence of any letter we’re looking for is removed. Only the first and not all because the search pattern may only use one letter up and it occurs more than once in the source word. This gives us back a parseable string that is of the right form.

This should really be a private method, but I found developing it using tests to be beneficial so left it public. The equivalent method in the Ruby gem is unreadable to me now.

In the main function we can use this like so:

Enum.reduce(@dictionary, [], fn str, list ->
if Regex.match?(search_pattern, str) do
[str | list]
else
list
end
end)

This will give us a list that matches the candidate pattern.

The job is not done yet.

  1. The words found can have multiple occurrences of characters that should appear only a certain amount of times from the source word.
  2. We may have been given a mask that contains letters that aren’t in the source word, which means it will find words that don’t match properly.

I think that solving this by hacking instead of testing is what made the Ruby code so difficult to understand.

The first problem is solved by adding a function that compares character counts;

def check_word(word_char_counts, source_char_counts) do
Map.keys(word_char_counts)
|> Enum.reduce(true, fn char, acc ->
acc and Map.get(source_char_counts, char) >= Map.get(word_char_counts, char)
end)
end

This takes two maps that contain the letter and the count of times it was used. I used Enum.reduce to and together a check that each letter isn’t used more times than it should be. The word counts are obtained from a helper function not given here.

Now we can filter the previous candidates

|> Enum.reduce([], fn str, list ->
if check_word(get_char_counts(str), source_char_counts) do
[str | list]
else
list
end
end)

The second problem is solved using these character count maps, by extracting their keys and diffing the lists you get back:

extra_letters = Map.keys(match_char_counts) -- Map.keys(source_char_counts)

if extra_letters != [] do
{:error, "Source word does not have letters '#{extra_letters}'"}

I decided to follow the convention of returning an error tuple. For logical consistency I should really return an ok tuple, but as I will be using the library myself I didn’t want to. Again, if I recall correctly, the Ruby code does this is a much more convoluted way.

The rest of the code is in the repository in Github if you’re interested.

The next thing is to create the first pass of the word finder on the web.

So, the Vicissitudes of Interviews?

I’ve recently gone through the process of finding another job. It was quite frustrating. I thought I’d write a few comments on the various processes I went through for fun and profit.

1. The code test that was an exercise in catching people out

For the record, I’ve taught classes on how to do Test Driven Development. I’ve also been writing software professionally since I did my sandwich year in 1985, started actual coding in 1983 (in those days we didn’t have many PCs or the Internet so most people didn’t code until they got to University). I originally learned to do it in Ruby at the European Rails conference in 2008 from (if I recall) one of the people who first contributed to RSpec. I’ve also run classes and written how to in languages other than Ruby (Perl and PHP – which were both interesting). I think it’s fair to say I know what I’m doing.

So I get asked to develop something using TDD. I get comments back saying these are the worst tests the person has ever seen, and some other fairly snarky stuff. I can only conclude that they have never seen anything developed with the TDD like you mean it concept. This means you start with a test that makes sure the class just loads and all of the libraries are in place, then you work outwards from there.

I did have the flu when I did this and may have misunderstood the brief. I did the infamous one small change just before I took myself to my bed and the cut I sent to github didn’t load – I was almost seeing double at the time but it was a silly mistake.

The thing is – if I was interviewing me I would have found myself wanting to have a conversation, if the brief had been misunderstood I would want to know why because that’s an interesting conversation in itself. If I had seen an unfamiliar way of constructing the tests I would have again wanted to talk to the candidate because there may be something to learn there. The software I wrote did indeed use the API and show stuff on the screen as requested – for some reason that wasn’t right, and I don’t care enough to find out why.

For the uninitiated, a lint program is one that goes through the code and looks for common errors. It sometimes formats things as well, but not always. I used the standard gem to do linting and checking and it found nothing. I have a habit when I just hammer Ruby code into the editor of not putting in new lines except between method definitions, and even then I sometimes I don’t bother. So my Ruby code straight off the press, as it were, can sometimes look a bit dense. But you can press the return key a few times, right? You’re a grown up. I should have done this, and had a last tidy of the code but as I said I could hardly focus on the screen at the time and I just wanted to close it out.

That hurrying and not just asking for a couple more days was a mistake and I own it. I don’t own the other faults the reviewer found. I also reject entirely calling the tests poor – I used to teach this stuff, I might know more than you and have a different approach. Your ignorance is showing. You could try talking to me – I’ve been doing this stuff for nearly 40 years – have you read my CV?

After this long I can read code in a variety of languages that may not be formatted at all well and (to be honest) I don’t notice. I might run the reformat command in my editor of choice (because sometimes you see indentation move in a way that indicates code blocks are formatted but the actual syntax tells a different story).

The rude review I saw was moaning about the code not being linted – it was linted to death, buddy. You mean formatted and you don’t know the difference. If you want a new line between definitions and before blocks say so in your spec. Standard doesn’t care about that, neither does RubyMine’s formatter. Your inexperience is showing and you probably aren’t even aware of it. I mean, provide a rubocop config file and be done with it.

I definitely feel I dodged a bullet if I would have ended working with the individual who wrote that review. Maybe they were having a bad day too, but I gave up an entire weekend, feeling rough as a bear’s bum and worse and worse as time passed, and a little bit of courtesy wouldn’t have gone amiss – from their comments they spent about 5 minutes and never even attempted to understand my approach. We would probably have had a falling out eventually if they turned out as arrogant as they appear to be.

2. That Gem you wrote is all wrong

I’ve recently been playing with word games on my phone and wanted a little tool that I could give me a list of options. To that end I wrote the silly Ruby gem werds that lets you do this. It has a deliberate design choice where it loads the whole dictionary it uses into memory once so it can be interrogated over and over again from the console.

Obviously, this won’t work that well in a web context where the gem might be loaded once per request and use up lots of memory that then has to be released. But for my uses and prototyping it was fine. Future versions of the gem might even load things up into a Postgres database and use regular expressions as queries.

I put this gem on my CV, because why not? Problem is, according to someone who looked at the gem the gem was wrong. I had made a deliberate decision that I might change in future. I’m not an idiot. I’ve been doing this stuff for a very long time. But instead of having a conversation with me about that choice the gem was wrong. Err, no, it works the way it works for what I consider to be good reasons that may change later.

So they decided not to go on with the interview process after the first interview (which I really enjoyed, by the way). I started to have a conversation with the recruitment agent about this and see if I could rescue the process, but then decided I couldn’t be bothered. I don’t play games and the incident had soured things for me.

So, if I didn’t have anything on Github at all, or didn’t mention that gem it might have gone forward.

Why play some game of gotcha and demonstrate you don’t know how to talk to someone with my level of experience? What was the benefit, there? Another bullet dodged, I think.

3. The one that didn’t get away

After the initial HR has this guy only got one head and can he speak coherently interview I did a very interesting exercise with a couple of people where we talked through the potential faults and improvements we could make to some Rails controller code. It was fun and let me establish a human relationship with them.

The final stage was me doing a simple but hard enough task using TDD – we did it together and they watched and I talked through my process.

Can you see the difference here?

First, they talked to me and got to know how I think. Second, they watched my process and had me explain it to them while we worked together on something.

These people know what they’re doing and I’m really happy to be going forward with them.

If you treat interviews as some off in the distance zero sum game you will probably not be able to find candidates who either have a depth of experience you’re not used to, an approach you’ve never thought of, or any one of a number of things that could help you with being more diverse or deeper in terms of experience. It’s not school, it’s not some sport, it’s work. You will end up with candidates who look and think like you do, because that’s what your rules will pull in.

Put away the childish things and talk to people. It may appear to take longer, but when there are very few people with the skills you need you don’t want to turn down a candidate because you haven’t got a clue why they approached a problem in a way you either don’t understand, or perhaps don’t agree with. I’ve been doing this stuff for some small while now, and I never do anything without a reason I can back up.

My approach to these exercises is always code is a conversation. If you end up not wanting to talk to me I’m more than happy not to – the chances are we won’t work work together well.

I will own that if you’re not feeling well, ask for more time and try later. That one was on me.

The newbie super power

If you’re new or junior in your job you can sometimes find yourself paralysed by how little you know. This can come from two different places:

  • Context. There are so many choices you don’t know where to start.
  • Fear. Your ignorance means you don’t know what to do to even try to start.

You can fix both of these by using your newbie super power:

Ask questions.

We’ve been taught in school that you’re not supposed to cheat, you’re just supposed to know things and teacher will be angry if you don’t. You were taught that cribbing from other people is bad.

But real life, in a real job, is not an exam. Everyone, selfishly, needs you to become productive and be able to make a contribution. The only way that can happen is if you ask what they need you to do. If you don’t understand, ask again. I would try something first, just so you have something to talk about and learn from, but asking is a super power.

Watch the people who are senior. They listen, and they ask. This is a superpower you need to master.

Today I rediscovered the Ruby double splat operator

Old Ruby hands will know that you can use the splat operator * to turn an array into a list of arguments:

def fred(x, y, z)
  puts x
  puts y
  puts z
end

argy_bargy = [1, 2, 42]

fred(*argy_bargy)

=> 1
=> 2
=> 42

There are also another trick you can do with this:

a = 1

puts [*a]

=> [1]

a = [1]

puts [*a]

=> [1]

Where the dereferencing lets you ensure you are always using an array. This is thought to be a bit old fashioned now and Rubyists now use the Array() method that does the same thing but with less syntactic magic. Back in the days before Ruby 2 (or so) it was the only way to do it.

I’m a great believer in trying to avoid the cardinal sin of Primitive Obsession – in Ruby this usually manifests itself as storing hashes everywhere and ending up with lots of code full of several levels of square brackets that manipulates them that ends up being parked in the wrong place. Ironically Rails is full of this and you often find yourself peering through documentation looking for the options hash to see what you can ask an object to do.

So in an ideal world you might want to be able to create object on the fly from hashes (say ones stored as JSONB in a Postgres database for instance 😉) that have some intelligence in them beyond the simple, somewhat cumbersome, data carrier that Hash offers. So you could try something like this:

Thing = Struct.new(:x, :y)

harsh = { x: 1, y: 2 }

wild_thing = Thing.new(*harsh.values)

The only problem here is you lose the useful semantics of the Hash, if it is initialised in a different order, or from a merge, then you’re screwed. The hash keys and the Struct’s keys having the same names is a mere semantic accident. This isn’t what you want. Instead let’s use the double splat:

class Thing 
  attr_reader :x, :y
  def initialize(x:, y:)
    @x, @y = x, y
  end
end

harsh = { x: 1, y: 2 }

wild_thing = Thing.new(**harsh)

You now have a way to create an object you can start adding methods to from your hash source that is isolated from argument order changes. There is one last wrinkle, which is that JSONB keys are strings, so you need:

hash_from_json = { "x" => 1, "y" => 2 }

wild_thing = Thing.new(**hash_from_json.symbolize_keys)

Now you’re almost ready to be able to take chunks of structured JSON and quickly and reliably turn it into usable objects with things like the <=> operator in them

instead["of"]["quoted"]["nightmare"]

That’s a Hash and nothing more. You can even add methods that implement [] and []= to keep Hash-like capabilities with a bit of meta programming, perhaps for backward compatibility, if you really have to.

I have arrays of these, that map to diary entries in an app I’m working on. I’m also very very lazy when I expect the computer to do the work, I want to solve problems once and they stay solved with as little fiddly RSI creating pressing shift to get brackets and things as possible. So:

class DiaryEntry
 attr_reader :name, :start_time, :finish_time

 def initialize(name:, start_time:, finish_time:)
   @name, @start_time, @finish_time = name, start_time, finish_time
 end
end

def apply_schedule(schedule, offset:)
  make_entry = -> (entry_hash) { 
    DiaryEntry.new(**entry_hash.symbolize_keys) 
  }
  all_entries = diary_entries.map(&make_entry)
  # ...
end

Code has been split across multiple lines to ease understanding. I now have a nice array of proper objects that I can filter and add to the map using methods instead of clumsy brackets everywhere. We can sort them and so on if we wish too.

This last example also shows one of my favourite techniques, which is to remap arrays of things using simple lambda functions, or use them with methods like filter inherited from Enumerable, a named lambda isn’t always necessary but it follows the useful pattern intention revealing name that can make you code much clearer. Using lambdas like this means then can also be passed as arguments to methods for filtering or formatting, that can be very functional-style without having to go all object-oriented.

For extra marks, dear reader, there’s a post on stack overflow that uses a technique like this to create structs from hashes on the fly. See if you can find it and come up with some uses for it, I’m sure there are many.

Phoenix: It was nice while it lasted

We decided to pull the plug on using Phoenix.

The people we know who are using it are mostly well funded and have the time to learn to use it and find their way around things that are a struggle.

We are not.

I wanted to do something that would have taken me five minutes in Rails and Phoenix just wouldn’t do it. Or, at least, the way to do it wasn’t documented.

I also got burned, and wasted a lot of time, because the Phoenix commands have been renamed to be phx instead of phoenix.

I ended up creating a Phoenix 1.2 app by mistake because the old command wasn’t deleted.

It’s annoying. I like the Elixir language a lot. But it’s back to Ruby on Rails because I don’t have time or the dime.

I think in about a year I might come back to it because it will be a bit more mature.

Notes on my first Ember/Phoenix app

I hit a bit of a problem. I’m writing a quotation system for my company.

I have an entity called EstimateType – it is the driver for the rest of the setup. Basically it’s a name and it’s used to group the pieces of the estimate together, so you have, say, small business, or sole trader, and they each may have the same parts of the quote but the details will be different (for example sole traders are generally taught one to one and we charge a flat fee not per delegate).

I built a prototype front end in Ember and used the mirage library.

Using Mirage I just sent the EstimateTypeId to the app and it worked.

The back end’s in Phoenix and I’m using a library called ja_serializer that’s supposed to support Ember out of the box. Having done some experimenting with hand building stuff that can talk to Ember I think this is a good idea and will save some time.

The code generated by this library puts the parent up away in a different part of the JSON from the main data, in a place called relationships. This would be fine (I suppose) but the ID doesn’t end up getting saved either by the generated controllers, or by the generated change sets (I had to add it in).

I’m really not convinced this is right.

10 Apr

The generator doesn’t do parent child properly. It essentially generates the same set of models, tests and controllers that you would get if there were no parent. This is a bit useless and is what got me confused.

I added in some more methods to the tests that create the parent entity and then put it into the queries and structs used by the wrapper methods in the Estimates module (which is the main one for this part of the app).

I’m still a bit meh about having to put things into a module for different parts of the app, which I think came in with 1.3. It’s nice, but often those decisions at the beginning of a development or design run will seem not quite right, and then you get into the problem of asking yourself if it’s worth moving things around. I’d far rather have the problem of deciding if it was worth pushing things into domains and/or namespaces because my app had become overcomplex. It feels like adding an extra layer of indirection for its own sake, and I’ve had enough of that from the days I used to write lots of Java.

Now I have a set of tests that run, and controllers that do parent child correctly.

I did get somewhat hampered where my CI system was failing and not deploying when the tests were running locally. Have since worked out that this was because

MIX_ENV=test mix ecto.reset

Has running the seeds built into the aliases. I’ve since added these aliases to my mix.exs file:

defp aliases do
 [
 "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
 "ecto.setup-noseed": ["ecto.create", "ecto.migrate"],
 "ecto.reset-test": ["ecto.drop", "ecto.setup-noseed"],
 "test": ["ecto.create --quiet", "ecto.migrate", "test"],
 ]
end

And now I do ecto.reset-test if I want to trash the test db. I still haven’t worked out how to tell mix to always run this with the test environment, but not worrying about that now.

I’ve also added

 {:mix_test_watch, "~> 0.5", only: :test},
 {:ex_unit_notifier, "~> 0.1", only: :test},

To my deps, so that I can run the equivalent of guard. Test watch autosets the environment to test but I added only: test because I didn’t want the dep in my production setup. It does mean I need to put MIX_ENV=test onto the command line or it won’t compile and run, but it’s no great hardship.

Later the same day

I must have used the wrong generator commands because this now seems to at least attempt to create the parent records

mix ja_serializer.gen.phx_api Estimates Estimate estimates company_name:string aspiration:string prepared_for:string email:string body:map estimate_type_id:references:estimate_types

The estimates tests now contain

estimate_type = Repo.insert!(%RosieEstimatesServer.Estimates.EstimateType{})

In the controller tests. The tests are still all busted, but at least there’s a starter for 10 there now where there wasn’t before. I still had to set up an alias for Repo, though.

And another thing

The autogenerated change sets don’t have the parent id in them – maybe they’re supposed to be used differently – but in the absence of any decent examples it’s a bit hard to get to the bottom of.

In all cases I’ve had to add estimate_type_id to the cast and validate_required clauses in the model files.

In addition

|> foreign_key_constraint(:estimate_type_id)

Wasn’t put in automatically, which seems a bit weird.

Meh

In order to get errors to be returned in a format Ember likes I needed to change views/changeset_view.ex so that it returned the errors in a compatible list

def render("error.json", %{changeset: changeset}) do
  %{errors: errors_to_json_format(translate_errors(changeset))}
 end

defp errors_to_json_format(errors) do
  errors |> Enum.map(fn {k, v} -> %{detail: List.first(v), source: %{ pointer: "data/attributes/#{k}"}} end)
end

As in the old format isn’t supported any more. This code needs a bit more refactoring but right now it works. Thanks to this guy for the tip.

Also Ember pluralises the entity name so the controller methods needed to be changed

- def create(conn, %{"data" => _data = %{"type" => "estimate", "attributes" => estimate_params}}) do
+ def create(conn, %{"data" => _data = %{"type" => "estimates", "attributes" => estimate_params}}) d

As in, pluralise the type.

Happy days.

And …

import { underscore } from '@ember/string';
...
keyForAttribute(attr) {
 return underscore(attr);
 }

In the serializer config – because elixir inbound wants underscores and I lost patience with JSON API sez X pedantry 🙂

Tumbleweed Interview Candidates

In my present role helping a team become more agile I was asked to help with some interviews. We must have talked to about ten people. The profile is relatively unusual: Object-oriented PHP with MVC and some Oracle PL/SQL. Unusual but a lot of people claim to have at least some of it.

I’ve helped conduct at least two interviews where you ask a straight question related to a claim on a CV e.g. claims about knowing Object-oriented design patterns, I get what I’ve come to call the tumbleweed response. As in what happens when someone makes an unfunny joke and there is silence. The idiom comes from the cowboy movie where the wind blows across the silent plains and makes the tumbleweed roll by; there is nothing there! (Reeves and Mortimer fans will know exactly what I mean).

So, if you are going to be interviewed by me, remember the following:

If you claim to have designed databases with hundreds of tables you should be able to explain what foreign keys and lookup tables are. Third normal form? It’s a dying art. Look it up or don’t make the claim.

If you claim to know PL/SQL then you know the difference between implicit & explicit cursors, probably what ref cursors are and what in, out and nocopy mean and why you would use them. Bonus question – what are PL/SQL tables (hint: nothing to do with database tables, it’s a language construct, so don’t start talking about database tables – it means you don’t have a clue).

SQL: inner and outer joins, foreign keys etc. Why as well as what.

If you know J2EE or Java beyond having attended a one-day course tell me what might go wrong with singletons (have a read up about serialisation)? How and why do you implement an equals method (just look it up)? Bonus question – if you have read about trying to create enumerated types in Bloch’s Effective Java are there any problems with it? Double bonus – tell me about synchronisation and the actual order statements can be executed when optimised that breaks it. It’s a feature. I’m a bastard question: why have’t you read Effective Java? Do you know what POJO is, and why does it have so much meaty goodness? (See Bootnote – some of this stuff has changed).

If you claim to be well-versed in object-oriented techniques you sure as christmas is coming need to be able to tell me the difference between has-a and is-a relationships, and why they are needed. Plus the usual stuff about abstract classes, interfaces and so on. Maybe, as a bonus question, why dynamic languages don’t need interface or abstract – or do they? I like people with opinions.

Ruby – what is duck typing? Can you explain what method_missing does? What does yield do? What’s the difference between a string and a symbol? How do you pass a block to a function – why would you? What’s a mixin and why do they taste so nice and chocolatey? Bonus: Why is the splat operator so handy?

Rails –  how does an @ variable set in the controller appear in the view? What tools to you use to test model/view/controller code separately and together? Tell me why fat model, thin controller is a good guideline. (This question also works for PHP/J2EE and whatever framework you want).

(I will think up more RoR questions – readers feel free to chip in and I will add them).

Agile: What does YAGNI mean? What does PIE mean? What is TDD? Then, of course, why? Bonus: Demeter/Tight and loose coupling/…

Patterns: Describe MVC (why as well as what). Do you know what the conductor pattern is? If you claim to know patterns such as Factory or Singleton, then expect to be asked “what does a factory give you” (concrete class that implements a known interface, like a database connector or cross-platform representation of a GUI object) or “why would you use a singleto” (global data store, or even a factory!) Bonus question – what does “concrete class” mean? Expect why questions – anyone can implement someone else’s pattern – why was it a good idea?

General Programming: How do you track production system bugs down (this is open ended – no right answer – but have some idea, please!) Why is refactoring old code generally a good idea? Or is it a bad idea? What’s refactoring anyway?

I can’t be bothered asking questions about XML but there are plenty – I leave that as an exercise for you, dear reader.

Some of these questions overlap, obviously.

Bottom line: If you claim to know something then expect to be asked about it – I will bone up on the web if I don’t know to do you the courtesy of being able to shine – I want you to succeed, honest.

Bottom line: Don’t make claims you can’t back up. Don’t waste my time.

Envoi: I don’t know is a fine answer, don’t be afraid of it. You get more respect for it. Just don’t sit there watching the tumbleweed after claiming to be a world expert on something – it makes us all so embarrassed.

Bootnote: 2015

I believe that enums are now part of Java and the daft problems where the compiler would sometimes re-order code outside of synchronized blocks have been resolved. Not so sure about the singletons not being singletons when they get moved from VM to VM problem though.

Coding Horror: Presentation: Be Vain

http://www.codinghorror.com/blog/archives/001007.html?r=21636#endcomments

I spent most of my spare time from age 8 to 16 learning to play the guitar and these instant gratification things just annoy me.

That said, I agree with the point that presentation is far more important that people think, and the example is a reasonable one. Please stop focusing on the specifics here – Jeff’s trying to make a very reasonable point.

Techies start from a data model and then wrap it with some half-assed forms from a generator – I know we do, I’ve done it myself lots. I learned that this does’t work because the logical view of the data isn’t the user’s view. Not listening to their pain and trying to help them get to where they want is arrogance. For example, on a system our users use (and I did’t write) they hate the way it takes forever to open the person details screen and all they ever want is the email address or phone number – a techie generated the user form out from the data model and joined it to the logically correct place. Imagine how much extra effort it would have been to put the phone number and email address on the summary? Hardly any, but it does’t fit the cod-head approach. I would lay money the coder has never talked to a user or watched one use the system.

The sexy unwritten thing is’t at all new. I worked on many projects in the pre-web days where the client had “bought the powerpoint”. Then they kicked us lots because it was all a lie.