1,355 karma · joined December 14, 2010
Rails and Mobile, Java and .NET in a former life.
The code very much looks like C# to me. It echos C# in both OOP style and organization: There are multiple classes per file (allowed in Ruby but not generally conventional). There are implicit Disposable interfaces everywhere -- I guarantee that somewhere there's C# code that says:
class MutableDisposable : Disposable
and so on.Also, class variables.
This doesn't look like a good-faith attempt at becoming involved in the Ruby community, but rather a C# port that was assigned to someone who had just enough Ruby experience to pull the code over.
I supposed that makes it somewhat understandable? It's clumsy, but it looks to me like the result of some PM or tech lead up in Redmond deciding that not porting ReactiveExtensions to Ruby was worse than a clumsy port to Ruby.
Weeell, but this (class-level state) is true of virtually all non-functional environments though, right? -- including the otherwise excellent concurrency support within the JVM.
If someone's using class/global state in a contentious, multi-threaded environment, they...probably should not be developing on that particular problem.
As you pointed out, the fact of class-level state isn't so much an argument against Ruby per se. To me it's more of an argument in favor of stateless/functional programming where data contention is high -- which is somewhat besides the point in this conversation because we're talking about (mostly) "embarrassingly parallel" concerns where data tends to be siloed and contention is low.
>> if I knew I needed heavy multi-threading for memory efficiency and CPU utilization I might disqualify Ruby on cultural reasons alone
But...aren't these exactly the kind of problems that REE/Passenger, Unicorn and Puma (not to mention EventMachine and Rack) have been digging into for years now?
As much of a bad rap as Ruby tends to get when it comes to threading, the GIL and so forth, I think what gets lost in that conversation is the fact that many flavors of Ruby application server configurations are serving thousands and thousands of concurrent requests in production every second and doing a pretty good job of it. In certain contexts, Ruby handles concurrency and parallelism admirably well.
"Culture" is a relative question -- are we talking about the guys at Phusion, or Engine Yard, or Heroku, or someone like Evan Phoenix, or Yehuda? Is that Ruby culture? There's some heavy threading brain-power in that group, and they've left a pretty big footprint on the Ruby/Rails community.
Or are we talking about (no offense) journeyman web coders who generally don't have to solve threading/high-contention, CPU-intensive problems all the time? I'm honestly not sure that at this point the Ruby community is any worse off than other communities in that regard.
In 2013, the Ruby/Threading issue is starting to feel (to me) a bit like the "Java is slow" notion did in the early 2000s. Might be time to look at what Ruby is actually doing in production and rethink that idea.
I think so, at least in environments where OOP is the base metaphor, like Ruby or Python. I can't think of any major impedance to creating meaningful class diagrams for, for instance, a system of ActiveRecord relationships. RubyMine (last time I used it) actually will generate a nice class diagram for you based on the given ActiveRecord/schema definitions.
For me these days, since not many coders use it, I find UML mostly helpful as a personal tool I use to understand a new codebase or a complicated design/data modeling problem.
I also find sequence diagrams really helpful, particularly in complex async, service-oriented environments where many times there's just too much state to track and too many moving pieces to really see the essence of the problem.
UML is not everybody's cup of tea, but I continue to find it a valuable way to visualize complex code relationships, often times surfacing problems/solutions that would not have been as transparent just from reading the code.
The biggest benefit to me has been that it expresses object relationships, imo, better than code. At a high level it's much easier to visualize fundamental design mistakes or solutions when object relationships have actual shape. OOP, for better or worse, was designed to model real world objects, actions or relationships, and graphical shapes, rather than sequential instructions, express that best.
I've found class diagrams very helpful for visualizing complex domains, and sequence diagrams extremely helpful when modeling service architectures especially.
I understand why many coders avoid it, but I also think it's unfortunate that UML has the reputation it does. I read Martin Fowler's UML Distilled (and I still recommend it) years ago. It made sense to me then, still does.
If a work is particularly bad, I'll generally just leave it alone, unless the artist has presented something that is obviously cynical and pandering, or otherwise obviously derivative and parasitic on the work of better artists. In those cases I might get slightly snarky. I try to control this and tone it down, because even derivative works are risks, and usually somewhat naive.
If the artists' ambitious goals weren't met, and I think I understand them, I try to lay this out in as constructive a manner as I can.
I can usually only accomplish good criticism by immersion -- repeated (dozens of) listens to a record for instance, over a period of days, writing/typing out lyrics by hand, listening to all the artist's previous records, reading as many interviews as I can and just trying to get my head in the "space" of the record. At some point I get to a place of sympathy where I get into the "soul" of the record and I really have something to say, that isn't just a first impression, nor a knee-jerk reaction, but as close to deep understanding as I can get. It's really hard work, even for just a 150 word review (which is one reason I don't do it often any more).
It's rare to get that kind of perspective on a HN comment, "Show HN", or some blog post linked here. But even with the noise that's emerged over the last few years as HN has grown, I can still find the really constructive comments and learn as much as I always have. I just have to look past the frustrating drive-by comments, the throw-away accounts and the axes-to-grind. The signal-to-noise isn't what it used to be, but in general there's just as much signal, but a lot more noise to have to overlook.
It's like a tools kata for my fingers. I run a few reps most mornings just to get warmed up.
My experience at large tables has been that good coders and PMs will actually IM a developer when they need to ask a question -- I do this all the time even when I'm sitting 2 feet from the guy I need to talk to: "let me know when you have a sec to talk about X", etc.
Again, that's evidence of a team that's generally on-task and communicating well -- a cultural quality that is itself harder to find than not.
Again, my sampling is based on the good fortune of working on really good, highly talented and focused teams. It's not perfect and certainly after months and years on the same team, you can lose perspective and think some things are worse (or better) than they really are. But I've been on really disfunctional teams as well, and some teams that I'd say were "in between". For those latter teams, I wouldn't recommend open-plan. To me, open plan is a high-risk, high reward proposition that takes commitment from the top down to make work over the long haul. But in my experience, the reward is high, and I really do prefer it.
My last two gigs have been open-plan, and I prefer it much more than closed-cube spaces. If your team is working as it should, and is in close proximity to project/product management, with a good process and a healthy level of trust between the stakeholders and between the various engineers, then in my experience open-plan is far better, because the quality of communication is high, the general focus of the team is high, and there's less background noise "distraction", because the cross-talk is usually relevant and on-task, and has a higher likelihood of being pertinent to the job at hand. Open plan offices work well when the team is already working well.
However, if there's broken processes, unfocussed coworkers, and a general level of distrust between team members or across teams, then the background chatter becomes exponentially more distracting and frustrating. Unfortunately most teams tend towards the latter and not the former.
In other words -- in my limited, anecdotal experience (last 5 years, two large open-plan teams; 10 years before that in closed or hybrid), high-functioning teams tend to thrive on the cross-talk and constant communication that open plan creates organically. Lower-functioning teams on the other hand have done better when the natural barriers of walls and closed doors limit unnecessary distractions and create healthier boundaries.
So it's not surprising to me that the study shows more instances of teams unhappy with open plans; it's certainly not for everybody. But the best teams I've been on have absolutely thrived in that environment.
FF is OSS (as far as that goes) and certainly not sitting still. Seems like the obvious dev choice to me these days.
I don't necessarily want that data in my session, or as a user attribute that I have to migrate the DB for. If it's a pkid or something that isn't necessarily sensitive, but I also don't want it to be too easy to get at, I might use a signed cookie.
Now, I've never actually done this... ;p
cookies.signed['some-id'] = model.id
Rails will use the secret here too. # Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
# ShopMobile::Application.config.session_store :active_record_storeLooking forward to porting my ant scripts to gradle.
As to OSGI -- that has been the core of Eclipse for nearly a decade, and IMO also a big part of the problem. The promise of OSGI was to allow Eclipse to be treated as a radically-open MDI framework that you could write just any old software on -- not just IDEs, but gaming frameworks, spreadsheet editors, on and on. The reality is that the standards for Eclipse's OSGI "drop-in" architecture have not stabilized into a robust ecosystem, rather it has lead to wildly varying user experiences, odd menu/pane/window configurations that have little consistency from one plugin to the next and poor quality software across the board. I'd be very reluctant point to Eclipse as an example of OSGI's fulfilled promise.
Also -- not sure if you read the OP, but the new Android IDE is going to be IntelliJ, not Eclipse.
But over the years the architecture has developed real instability. Frequent crashes, terrible and fundamentally broken package/dependency management. Difficult to find features, inconsistent UX and a vast amount of very low-quality plugins in the ecosystem.
Then there's the extremely varied and confusing set of packages. There's even a matrix of packages and features to help you decide! But even that grid barely scratches the surface:
http://www.eclipse.org/downloads/compare.php
Using Eclipse over a period of months creates an ongoing feeling of anxiety and fear of project file corruption. Updating a plugin is a crapshoot. Dead repository links abound, installs and upgrades have a high likelihood of failing. Upgrading Eclipse itself is like playing routlette with your project file.
Two years into using IntelliJ, I'll never look back. I used to be a huge Eclipse fan, used it for many years, but it just hasn't aged well at all -- it's a layered-over Frankenstein that barely resembles its former greatness.
I'd guess it's going to something akin to the difference between JetBrains' RubyMine and Ruby/Rails plugin support inside IntelliJ -- same overall functionality with better UX integration for the domain.
tl;dr -- Yes!
The non-tl;dr:
By "surplus of content" I meant to say that the rich, english-like syntax of something as high level as a Ruby DSL acquires rhetorical, intuitive meaning that cannot be reduced to a 1:1 symbolic relationship to the compiled instructions. But this "surplus" is supplied by the perceiving subject, in the same way that natural language itself is interpreted and redacted by the human being reading a particular work.
I didn't mean to say that mathematical magic had happened as a result of complexity.
I'm coming at this from a philosophical as well as a CS background (I studied both, but ended up in software). In philosophy, there is an ancient tension between rhetoric and logic. Logic is a brute force process -- a set of rules where the same input always produces the same output, just as (and, it turns out, according to the same rules) the same electrical series of pulses supplied to logic gates and pushed lockstep through them by the CPU clock will always produce the same output. Many analytic philosophical papers don't look all that different from a Karnaugh map describing the structure of a multiplexer, and the results of both are equally deterministic. This school of thought was galvanized by and built heavily upon the Principia we spoke of earlier.
But there's another school of thought in philosophy that uses rhetoric and poetic devices as well as logic to achieve its ends. Language in this view (From Aristotle's Rhetoric to Heidegger's Building, Dwelling, Thinking) is decidedly not deterministic, but provocative, emotive and intuitive. Human beings communicating with each other with language use analogy and a commonly shared narrative history to provoke meaning to each other, rather than reduce statements to mere facts that are reduced to true or false. This school is commonly referred to as the "Continental" school, due to its prominence in France and Germany. Analytical approaches dominate British and American universities.
So, my argument here is a function of a larger question about language itself. I'm saying that the English-like analogical techniques even at the lower levels are provocative and provide more meaning than can be reduced to the underlying logic. This is not to say that any software is less than deterministic -- of course it cannot be non-deterministic because the core functions are purely mechanistic and deterministic. So, an address changed in a DB is always changed in the same way, and a joystick moved in such a way to provide a stream of x,y coordinates to a controller will always move a character in the same way, etc.
But the meaning on the other side of those events is supplied by a subject. At an extreme level, think of a high-resolution bitmap of Rembrandt's Philosopher in Meditation. The presentation of the pixels is deterministic, but the meaning is supplied by the subject. I'm saying that to a greater or lesser degree this redaction, the interpretive gesture that supplies a surplus of meaning is taking place at basically every level of computation. To a lesser degree at the low levels ("push", and so forth), but to higher degrees the closer to English-like (3G languages, etc.) we get. Images and literature presented in UTF-8 are just radical examples on one side of the spectrum, of how deterministic CPU instructions can result in this "surplus".
>> The point of what I was saying was to refute the idea that somehow our programs are so complex and have such amazing behaviour that they will not be reducable to a core set of rules. If the programs run on a computer they must be computable and thus reducable to a core set of rules. That's it.
Considering a piece of software as a mathematical construction -- let's say, for instance, a C++ program compiled by the LLVM, and the LLVM bytecode expressed as machine instructions for the given chip, reduced to pure binary math, I totally agree with this.
"The instructions in the CPU are no different from the statements in the Principia"
As the goal of the PM was to show that math was a function of logic, we can use 'statements in the Principia' and 'the classical rules of logic' interchangeably in this context.
There's two questions at play in this conversation. One is whether in principle the question of the meaning, as such, of software, can be considered apart from the whole act of perceiving the software, either as code or as the final UX.
As the idea of "meaning" always involves some kind of communication, a sign or set of signs shared between two subjects, and as the idea of software pointing back to its own internal state as the content of this communication would render the communication pointless and the signs merely tautological, I think the question of meaning must bring the subject, and the act of perception and interpretation, into consideration. Scientific statements of fact, regarding the physical position of all of the machine's atoms and electrons, have content, but not "meaning" in the common sense of that term intended in the current context.
The second question, which I'm pretty much winging here (although I have long-held opinions about the PM and its relationship to the same kinds of considerations about "meaning"), is whether CPU instruction sets, as subsets of the rules of logic, dictated by the fundamentals of CS (Babbage, Turing, et al), are "pure" expressions of logic, or whether in the act of abstracting logic into the restricted set of instructions, we've performed an analogy.
I think the same question comes to bear -- it matters which perspective you're taking, whether "meaning" is merely a construction that hides the more essential question of physicality, or whether ideas like "push" applied to things like registers and addresses and binary values are linguistic in nature and convey more than just tautological facts about the physical state of CPU internals.
I guess this pushes the question out -- why does a computer exist? To represent to the world the bare facts of its own internal state? Of course not. A 64-bit address that points to a sequence of binary values is never just that, it's always a sign that points to something else -- a person's address; a representation of an English character; a shipment of goods; a lat/long location of some specific place in the world.
So, a "move" or "shift", to you, may reduce backwards to a collection of logical operations. But even there, what has happened? Nothing's "moved" or "pushed", that's just an linguistic trick to help us think of the electrical currents being turned "off" and "on" (and even those are analogies) in mentally-manageable concepts that map to the rules of logic. To me the question of "meaning" has already been broached at this point, if we wish to see computations as significant beyond, again, tautological statements about CPU internals. If we take the latter point of view, we have mere mathematical statements that have the same point as pure math -- the elegance (if that) of its own proof, not any relationship to something external to itself. But of course, that was never the real point of computers from the very beginning.
The Godel/Russell/Whitehead question is apt here, because this is a very similar question, if not the same question. Is math a function of logic -- that is to say, can math be "true"? The point of the Principia was to bring about the dream of the Vienna Circle, a purely mathematical and systematic technical language to resolve all philosophical ambiguity once and for all. While there remain a few holdouts for that dream, the general consensus is that this did not work out -- Godel was only one of many problems with Positivism specifically, and I would argue, Analytical Philosophy in general, although in recent years the Analytical/Continental divide has been shortened.
"What is logic made of?"
Yeah. This. That's the question driving all of this.
Good conversation.
But this isn't the whole story either, right? What is "pure boolean logic" anyway? It doesn't exist even at the lowest levels. Logic is always applied to a statement of some kind, it doesn't exist as a pure abstraction. It's interesting you bring up Godel. Russell and Whitehead attempted to map logic to math in the Principia, and were refuted by Godel's incompleteness. I don't want to make too much of incompleteness (as many do), but let's not make too little of it either. At some point logic can only do so much for you, and you have to resort to analogy. I think this happens much earlier in CPU architecture than you're allowing for.
What you have at a low level on the CPU are a set of instructions arbitrarily (to some degree) defined to efficiently model analogical actions like "push" and "move" and "shift" and the fundamental operations that map to assembly. And here we've already moved out of the realm of pure logic -> math envisioned by Russell and we've created logic -> language, by way of analogy. This is, I would argue, a rhetorical move rather than a logical one. We've already prepared/redacted the ones and zeroes for human consumption, and assumed a specific semantic to provide for a human imagination that will accept and adapt to the semantic.
But of course that's not what we do as coders. The code is never "complete" -- it's always striving towards some "meaning" that is for a human being. You cannot exclude the meaning of the code from the subject that it is intended for. A human being perceiving the code is always redacting the meaning of the code, not as a function of ones and zeros, but as a function of the analogy that code creates, pointing not towards electrons but towards: a product in a warehouse; a sum of sales at the end of a quarter; a flaming ball of death hurling towards my first-person-virtual head. And so on.
In this sense the electrons/ones and zeroes are no more significant than the paper that The Iliad is written on + the ink it is written with.
One quibble -- I would prefer non-negative(!) terminology, i.e., what is a "nonsymbol"? A collection? A monad? A duration? An event? A process? A closure? Some category that encompasses all of these? If so, can we find a positive semantic rather than negative?
>> Object-oriented programming hasn't stepped away from the full space of nonsymbolness-- and that's a big part of why it's so damn hard to reason about it.
Well, this gets back to the ancient problem of "The Third Man" and categories in general, right? One must categorize and "contain" meaning, trap it in language a moment in order for it to remain meaningful, but paradoxically the external thing that it symbolizes is always changing, so it's always escaping any semantic trap we set for it. This of course has practical (concurrent) implications in software as well as the high-falutin metaphysical stuff Plato was talking about.
These days I'm starting to wonder more about how we may not be using state-machines quite as effectively, or as often, as we might -- changing functionality more aggressively as the data changes, in order to move towards a better analogy with the ever-changing "real world" that software is trying to model. Might this be more self-aware starting place to integrate functional and object concerns -- both of which are necessary?
EDIT: A minor quibble: maybe "phenomenalist" isn't the best term to use in close proximity to Husserl. He used the idea of "phenomenalism" in contradistinction to "phenomenology" -- the former being a kind of reductionist approach to seeing essences as merely the "contents of consciousness", and the latter -- which is to say the general Husserlian approach -- sees essences, or "eidetic objects" as phenomena that intend towards the external world, at least external to subjectivity.