I am creating an [Iron]Ruby project that needs to support several environments (more specifically, WPF, Silverlight, and WinForms - but that's not as important). The following is an actual, concrete example of where I'm stuck:
I have to implement a Bitmap class as part of a library, and this class will need to be implemented differently depending on what environment it's running in (e.g. if I'm running this in the browser as a silverlight app, I won't have access to methods that would be available on the desktop). And here's the catch - I don't control the instantiation of Bitmap, nor any of the other classes within the library. Why? Because it's a port of another application; and, while I do have the code for the application, I don't want to break compatibility by changing that code. I do, however, control the entry point to the application, so I can require whatever I need, perform setup, configure global variables, etc.
Edit: If you're curious, this is the project I'm working on:
http://github.com/cstrahan/open-rpg-maker
Here's what I want to know:
How should I set the configuration at startup, such that Bitmap will behave appropriately?
How should I structure this in my git repo / source tree?
Here are some of my thoughts, but I'm sure you'll have better ideas:
How should I set the configuration at startup?
When distributing the app, place a require at the top depending on the targeted environment, like so: require silverlight/bitmap. In this case, lib/bitmap.rb would be empty, while lib/silverlight/bitmap.rb would contain the implementation. Or...
Stuff all implementations in lib/bitmap.rb, and conditionally execute based on a class instance variable or constant: Bitmap.impl = "silverlight". Or...
Maintain a separate branch for each distro - despite the library being almost exactly the same.
How should I structure this in my git repo / source tree?
Separate branches per distribution. Or...
Separate implementation-specific subfolders (e.g. lib/silverlight/bitmap.rb).
Being very new to Ruby, I'm not very familiar with such best practices (I'm coming from C#). Any advice would be greatly appreciated!
-Charles
Related
[Note: This question is, I think, dealing with the consequences of what prompted this never answered question]
I have a workspace that includes both a framework target and an application target. When I run the application many messages of the following form come to the console: Class "C" is implemented in both "Binary1" and "Binary2". One of the two will be used. Which one is undefined.
Here is a sampling of those messages:
objc[65093]: Class FIRAIdentifiers is implemented in both /Users/Robert/Library/Developer/Xcode/DerivedData/GenerationOfNow-bmsridmvnbtgfiduzqqomicqvsns/Build/Products/Debug-iphonesimulator/VerticonsToolbox.framework/VerticonsToolbox (0x10804bd20) and /Users/Robert/Library/Developer/CoreSimulator/Devices/33628599-9570-4784-B324-DAC383435F75/data/Containers/Bundle/Application/26411B80-FB71-44E9-AA64-05FEF20B9F08/GenerationOfNow.app/GenerationOfNow (0x10674a150). One of the two will be used. Which one is undefined.
objc[65093]: Class FIRASearchAdReporter is implemented in both /Users/Robert/Library/Developer/Xcode/DerivedData/GenerationOfNow-bmsridmvnbtgfiduzqqomicqvsns/Build/Products/Debug-iphonesimulator/VerticonsToolbox.framework/VerticonsToolbox (0x10804bd70) and /Users/Robert/Library/Developer/CoreSimulator/Devices/33628599-9570-4784-B324-DAC383435F75/data/Containers/Bundle/Application/26411B80-FB71-44E9-AA64-05FEF20B9F08/GenerationOfNow.app/GenerationOfNow (0x10674a1a0). One of the two will be used. Which one is undefined.
objc[65093]: Class FIRAZeroingWeakContainer is implemented in both /Users/Robert/Library/Developer/Xcode/DerivedData/GenerationOfNow-bmsridmvnbtgfiduzqqomicqvsns/Build/Products/Debug-iphonesimulator/VerticonsToolbox.framework/VerticonsToolbox (0x10804bde8) and /Users/Robert/Library/Developer/CoreSimulator/Devices/33628599-9570-4784-B324-DAC383435F75/data/Containers/Bundle/Application/26411B80-FB71-44E9-AA64-05FEF20B9F08/GenerationOfNow.app/GenerationOfNow (0x10674a218). One of the two will be used. Which one is undefined.
All of the duplicated class definitions come from Firebase frameworks which were installed into my workspace via the Pod file demonstrated in this question. Here is a screen shot of my workspace's Navigator:
Notice that both the framework target (VerticonsToolbox) and the application target (GenerationOfNow) are referencing the pods.
It seems to me that the proper way for a framework to be built is that it should not embed whatever frameworks it is linked against. It should be the responsibility of whatever application uses that framework to pull in the other dependencies. And indeed, when I examine the build phases for the framework VerticonsToolbox there is no option for specifying embedded binaries whereas there is for the application GenerationOfNow.
So, I am at a lose as to how to proceed. I suspect that what is happening is a result of the things that are put in place when pod install is executed. Can anyone advise me?
BTW: Can anyone point me to a good write up on how Xcode builds, what the various settings are, what tools there are for examining the binaries, etc? With Xcode everything is fine until it isn't and then there is this big, mysterious soup of stuff. Jeez!
I'm currently using a method where I have a "base" file that defines the types, interfaces and a basic API for the package. I then create an _windows.go and _linux.go file and add platform specific types that I can apply the interface to. The setup is basically like this: http://play.golang.org/p/2DJxTuSAIh.
Is this considered best practice?
Would this assist in a team setting where some developers are linux focused and some windows focused, i.e. if the interface changes both teams will be notified via build failure?
The use of interfaces is an orthogonal concept. Use an interface where an interface makes sense, but it's often simpler just provide an implementation by the same name in the proper GOOS and GOARCH files.
The method of using a common constructor name (from your example) is also used in places in the std lib, as is the method of assigning a global variable name to a function (which is similar in concept to the former method).
Because Go is statically typed, and you can't redeclare global identifiers, the build system will always catch problems; it's just a matter of testing for all applicable systems to ensure that no OS or ARCH has an out of date implementation.
What is best practise with regard to the placement of Interface types.
Often the quickest and easiest thing to do is place the interface in the same project as the concrete instances of it - however, if I understand things correctly this means that you are more likely to end-up with project dependency issues. Is this a fair assessment of the situation and if so does this mean interfaces should be separated out into different projects?
It depends on what you want to do. You're correct that placing interfaces and classes in the same assembly will somewhat limit the usefulness of the abstraction of said interfaces. E.g. if you want to load types in an AppDomain with the purpose of unloading these again, you would typically access instances via the interfaces. However, if interfaces and classes are in the same assembly you can't load the interfaces without loading the classes as well.
Similarly if you at a later point want to supply a different set of classes for one or more interfaces you will still get all the old types if they are in the same assembly as the interfaces.
With that said I must admit that I do place interfaces and classes in the same assembly from time to time simply because I don't think that I will need the flexibility, so I prefer to keep things simple. As long as you have the option to rebuild everything you can rearrange the interfaces later if the need arises.
In a simple solution, I might have public interfaces and public factory classes, and internal implementation classes all in the same project.
In a more complicated solution, then to avoid a situation where project A depends on the interfaces in project B, and project B depends on the interfaces defined in project A, I might move the interfaces into a separate project which itself depends on nothing and which all other projects can depend on.
I practice "big systems can't be created from scratch: big systems which work are invariable found to have evolved from small systems which worked." So I might well start with a small and simple solution with the interfaces in the same project as the implementation, and then later (if and when it's found to be necessary) refactor that to move the interfaces into a separate assembly.
Then again there's packaging; you might develop separate projects, and repackage everything into a single assembly when you ship it.
It is a deployment detail. There are a few cases where you have to put an interface type in its own assembly. Definitely when using them in plug-in development or any other kind of code that runs in multiple AppDomains. Almost definitely when Remoting or any other kind of connected architecture.
Beyond that, it doesn't matter so much anymore. An interface type is just like another class, you can add an assembly reference if you need it in another project. Keeping them separate can help controlling versioning. It is a good idea to keep them separate if a change in an interface type can lead to wide-spread changes in the classes that implement them. The act of changing the [AssemblyVersion] when you do so now helps troubleshooting deployment issues where you forgot to update a client assembly.
My question isn't so much about use of interfaces but more of a project organization nature.
Note: I am using VisualStudio in a multi-layered application.
Should my Interface files live in a separate project from their implementations? My initial thought is that it would be useful to separate out all my service interfaces into their own project (and a project for my initial implementations) so that down the road the implementation/concrete project may be removed and replaced with a new one if necessary.
To clarify with an example: Suppose I have a business layer Interface called IBusinessService which lives in the MyApp.Business.Services namespace. My implementation FooBusinessService would exist in the same namespace, but a different project in VisualStudio. If later on the implementation needed to be reworked, a developer could remove the reference to the FooService.proj and replace it with a reference to BarService.proj.
This seems like it would declutter the app solution by allowing you to reference a project with only interfaces without also acquiring concrete implementations (which may be obsolete or of no use to you), but am I missing something?
I'm with you. I prefer to put my interfaces in a separate project AND in a different namespace. The classic example is with data access classes. You want to be able to code an MSSQL version and a MySQL version, both implementing the same interface. As such, I prefer that the interface definition be in a separate assembly/project. Here's an example of how I lay out assemblies and namespaces:
Elder.DataAccess.Core - contains the interfaces and common utilities
Elder.DataAccess.MSSQL - specific MSSQL implementations of the interfaces
Elder.DataAccess.MySQL - specific MySQL implementations of the interfaces
This allows me to modify the implementations without touching the project that contains the interface definitions. This helps me with version control and change tracking, too. There might be other ways to skin this cat, so I'll be eager to see other folks' answers.
In Java when you compile a .java file which defines a class, it creates a .class file. If you provide these class files to your coworkers then they cannot modify your source. You can also bundle all of these class files into a jar file to package it up more neatly and distribute it as a single library.
Does Ruby have any features like these when you want to share your functionality with your coworkers but you don't want them to be able to modify the source (unless they ask you for the actual .rb source file and tell you that they want to change it)?
I believe the feature you are looking for is called "trust" (and a source code control repository). Ruby isn't compiled in the same way that Java is, so no you can't do this.
I have to say your are in a rough position, not wanting to share code with a coworker. However, given that this is an unassailable constraint perhaps you could change the nature of the problem.
If you have a coworker that needs access to some service provided by a library of yours, perhaps you could expose it by providing a web/rest service instead of as a .rb file.
This way you can hide your code behind a web server, and if there is a network architecture that allows for low latency making these service calls, you can effectively achive the same goal.
Trust is a lot easier though.
edit:
Just saw this on HN: http://blog.astrails.com/2009/5/12/ruby-http-require, allows a ruby file to include another file through http instead of the filesystem.
Ruby is
A dynamic, interpreted, open source programming language with a focus on simplicity and productivity.
So like all interpreted languages, you need to give the source code to anyone who want's to execute your program/script.
By the way searching "compiled ruby" on google returned quiet a few results.
I don't think there is one. Ruby is purely an interpreted language, which means ruby interprets your source code directly in order to run it. Java is compiled, so there's an intermediate bytecode (the .class). You can obfuscate your ruby if you really wish, but it's probably more trouble than it's worth.
Just to make sure you realize, however, upwards of 95% of Java can be decompiled back into source using various free utilities, so in reality, Java's compilation isn't much better than distributing Ruby source.
This is not a language specific problem and one that can be managed more effectively through source control software.
There is a library called ruby2c that compiles a subset of Ruby into C code (which you can then compile into native code, if you want).
It was actually originally written as a Ruby code obfuscator (but has since been used for lots of other stuff, including Ruby Arduino development).