Hacker News new | past | comments | ask | show | jobs | submit login

It's a well written version of, "our software design was sloppy and our programmers took shortcuts. Therefore language feature X is to blame."

  def findAddress(userId: String): String
  What does it do? Are you sure?

  Now lets look at another:

  def blah(foo: UserId): Address
What about

  def find_address_of_user( UserID )
or even better

  class User(Model):
     address = our_models.AddressModel( … )
So you can use 'x = user.address' with no need to explicitly map between users and addresses because the mapping is part of your data structure?

In some scenarios, Hungarian notation might make sense:

  def user_address(user):
In Hungarian notation you explicitly state what kind of data is expected, so that you can easily determine if mistakes are being made in the code:

  billing_vcard = contact_vcard(customer.billing_contact)
as opposed to:

  display_vcard = contact_email(customer.billing_contact)
Of course, cue the irrational knee-jerk reaction to "Hungarian notation" by people who don't understand what it actually is.

  OO lore has it that pattern matching is evil, and that subtype-polymorphism is the answer to all questions.
Not the OOD that I've been taught. Polymorphism is a tool, and it is as much the answer to all questions as a screwdriver is the answer to all construction projects.

That the author of this piece has found various languages educational in presenting new ways of solving problems (with code smells, data model smells, or sloppy architecture) is the biggest take-home message for me: don't be a "Perl programmer" or a "Scala programmer". Be a software engineer, and make sure you are aware of all the available architecture rules, modelling guides and design patterns that have been developed over the years to make your job easier.

Perhaps I'm missing something due to having read through the article too quickly. Please educate me.

Hi Manicdee! The point is that with any unityped representation you can come up with, the name tells you nothing certain; any conclusions you think you can draw from it are pixie-dust and moonshine. Even with nonsense names, the argument and return types give you solid proof not only about what the method does, but importantly what it _doesn't_ do.

There's no criticism implied of my colleagues at all -- I'm as culpable as anyone. The point is though, we can make big improvements with types, without paying a big cost.

You must have had good OOD teachers: http://c2.com/cgi/wiki?CaseStatementsConsideredHarmful http://c2.com/cgi/wiki?SwitchStatementsSmell


My apologies, I didn't intend to suggest that laziness and sloppiness were attributes of the programmers, but evils imposed by time pressure.

Do I fight management to get the two weeks I'll need to write feature X correctly, or just take the obvious shortcuts to get it done in 1 week?

Of course my laziness shows through because I haven't been in management's ear for long enough beforehand that they decided to give me one week without consulting with me ;)

I display this "lack of bottom-up management" failure mode consistently, I'm more interested in writing code :\

As for my OOD teachers, I've had mountains of bad Perl and PHP code to wade through, and the benefit of Stack Overflow and the Django Project to guide my thinking on the matter.

Type systems do provide some compiler-level assistance in the march towards coherent, well designed software, but they won't solve problems like

  def position_sprite( top_left: point, sprite: sprite)
When you provide the top_left of the wrong element (e.g.: confusing the top left of the drawing space with the top left of the window or display area.

I believe phantom type should help with your example. At it's most naive, you need a type for the points in window space, and a second type for the points in drawing space. If you give the sprite a window_point, it will complain about only accepting drawing_points. Now such errors are confined to a conversion function.

With phantom types, a the Point "type" would be a function of types to types. It helps when some operation work on all kinds of points: they can be polymorphic with respect to the additional type.

  data Point a = Point Int Int

  draw_sprite  :: Point Drawing -> sprite -> Io ()
  draw_button  :: Point Window  -> sprite -> Io ()

  translate_point :: Point a -> Point b -> Point a
  translate_point (Point x y) (Point xt yt) =
      Point (x + xt) (y + yt)

> Perhaps I'm missing something due to having read through the article too quickly. Please educate me.

The point I got out of this fine article is that we are under/misusing types.

Types encode logical propositions. The compiler, besides producing binary code, is also a proof checker. We should let it help us reason about the program instead of trying to do everything informally in our heads.

It is not as much feature X, but lack of feature X that's the problem in the article. Statical typing is a tool you should be using if it is suitable to your problems. The problem described is verifying there is no garbage in garbage out situation for your functions. Proposed solution is making compiler do the check instead of manually checking the codebase, writing more code known as TDD, enforcing conventions that are easily confusing... Common theme in these alternatives are necessity of extra tools and all associated effort. Compiler can be a perfectly servicable point of enforcement if types are used properly with possibly no extra cost.

My completely subjective opinion:

OOP is a valid way to write strongly typed code, but there are many useful and common situations that can be solved by some primitive feature found in any good functional language, where the OOP solution is verbose and counter-intuitive.

And that partly explains why so many people bypass the properly designed, strongly typed, object-oriented solution and write shitty code instead.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact